You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x64系统中能否利用uint64_t子位存储指针可靠访问mmap缓冲区?

自定义动态内存分配器:64位元数据字段存储指针、大小与标志的可靠实现

问题描述

我正在构建一个自定义动态内存分配器,使用大小为8 << 20(8MiB)的mmap缓冲区作为堆。mmap缓冲区的实现代码如下:

memory_buffer::memory_buffer() {
void* buf = mmap(nullptr,    // maybe set a 40bit addressable addr?
    this->size,              // Buffer should be 8 MiB big
    PROT_WRITE,              // We want to read and write the buffer
    MAP_ANON | MAP_PRIVATE, -1, 0);
                     
assert(buf != MAP_FAILED);
this->buffer = (char*) buf;
}

我预留了缓冲区的前2048字节存储空闲分配元数据,剩余部分作为可分配堆空间。我的需求是:

  1. 元数据结构体尽可能小;
  2. 结构体大小为64*n位(出于对齐考虑)。

我计划使用如下元数据结构体并拷贝到mmap缓冲区中:

struct freed_allocation{
uint64_t ptr_and_size_and_flag; //bitmasks to access relevant fields. (flag:1bit, size:23bit)
}

我希望用剩余的40位存储缓冲区位置指针,请问是否存在可靠的实现方法?


可靠实现方案

你的思路完全可行,核心是用偏移量替代完整指针存储,结合固定的缓冲区基地址实现指针的可靠转换,具体方案如下:

1. 用偏移量替代完整指针

由于所有可分配内存都在同一块连续的8MiB缓冲区中,不需要存储完整的64位指针,只需要存储空闲块相对于缓冲区基地址的偏移量即可。8MiB的最大偏移量仅需23位就能容纳,远小于你预留的40位空间,完全满足需求且有冗余空间可用于扩展。

2. 位段划分与封装操作

按照你的规划,对uint64_t字段做统一的位划分(以下示例从低位到高位排列,可根据习惯调整):

  • 第0位(最低位):空闲标志位(1表示空闲,0表示已分配)
  • 第1~23位:空闲块大小(共23位,最大支持8MiB,匹配缓冲区容量)
  • 第24~63位:空闲块相对于缓冲区基地址的偏移量(共40位,冗余空间可留作后续扩展)

用宏和内联函数封装位操作,避免直接写位掩码出错:

// 位掩码定义
#define FLAG_MASK 0x1ULL
#define SIZE_MASK 0x7FFFFFULL
#define OFFSET_MASK 0xFFFFFFFFFF000000ULL

// 提取字段
static inline bool get_is_free(uint64_t data) {
    return (data & FLAG_MASK) != 0;
}

static inline size_t get_block_size(uint64_t data) {
    return (data >> 1) & SIZE_MASK;
}

static inline size_t get_block_offset(uint64_t data) {
    return (data >> 24) & ((1ULL << 40) - 1);
}

// 打包元数据
static inline uint64_t pack_metadata(size_t offset, size_t size, bool is_free) {
    uint64_t data = 0;
    data |= (static_cast<uint64_t>(offset) << 24);
    data |= (static_cast<uint64_t>(size) << 1);
    data |= is_free ? 1 : 0;
    return data;
}

3. 偏移量与指针的转换

从偏移量转回实际指针时,直接用缓冲区基地址加上偏移量即可,只要不munmap该缓冲区,这个转换就是完全可靠的:

char* buffer_base = this->buffer; // mmap缓冲区的基地址
size_t block_offset = get_block_offset(freed_block->ptr_and_size_and_flag);
void* block_ptr = buffer_base + block_offset;

额外注意事项

  • 你的freed_allocation结构体大小为8字节(64位),天然满足64位对齐要求,符合需求;
  • 位段划分规则要全局统一,避免因位序混乱导致的错误;
  • 冗余的17位偏移量空间可后续用于存储额外标记(如块类型、合并标记等)。

内容的提问来源于stack exchange,提问作者6charm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:55:22