如何在C++中实现可限制内存大小的Object Buffer对象缓冲区
方案解答
1. 准确统计内存用量的实现
你提到的Hook STL分配器的思路是完全可行的,也是C++场景下最接近准确统计的方案,实现成本并不高:
- 自定义一个符合STL分配器规范的
CountedAllocator,核心逻辑非常简单:- 每次调用
allocate()分配内存时,把实际分配的字节数累加到绑定的计数器上 - 每次调用
deallocate()释放内存时,把释放的字节数从绑定的计数器上减去
- 每次调用
- 把
ComplexStructure里所有STL容器的模板参数都替换为使用这个自定义分配器,示例修改如下:
// 提前声明分配器、缓冲区类 class ComplexStructureBuffer; template <typename T> class CountedAllocator; class ComplexStructure { private: using MapAlloc = CountedAllocator<std::pair<const AAA, BBB>>; using VecAlloc = CountedAllocator<CCC>; using UMapAlloc = CountedAllocator<std::pair<const DDD, EEE>>; std::map<AAA, BBB, std::less<AAA>, MapAlloc> struct1; std::vector<CCC, VecAlloc> struct2; std::unordered_map<DDD, EEE, std::hash<DDD>, std::equal_to<DDD>, UMapAlloc> struct3; public: // 构造函数传入分配器实例,和所属缓冲区绑定 explicit ComplexStructure(MapAlloc map_alloc, VecAlloc vec_alloc, UMapAlloc umap_alloc) : struct1(map_alloc), struct2(vec_alloc), struct3(umap_alloc) {} void generate_some_data(); void delete_some_data(); };
这个方案统计的就是STL容器实际调用堆分配接口申请的内存大小,误差仅来自内存对齐的固定开销,对绝大多数场景都足够准确。
2. 多缓冲区关联的实现
完全不需要全局变量,通过分配器实例绑定对应缓冲区即可:
- 给
CountedAllocator添加两个指针成员:size_t* total_size、const size_t* max_size,分别指向所属ComplexStructureBuffer的size和max_size成员 ComplexStructureBuffer调用create()方法生成新实例时,先构造一个绑定了自身size和max_size的CountedAllocator实例,再把这个分配器传给ComplexStructure的构造函数- 可以直接在分配器的
allocate逻辑里添加校验:如果分配后总大小超过*max_size,直接抛出异常或返回错误,上层调用generate_some_data时捕获即可判断缓冲区是否已满,不需要在业务代码里额外手动判断。
极简适配方案(容忍少量误差时可选)
如果你的程序对内存统计误差容忍度在10%以内,不想碰STL分配器的相关逻辑,可以用更简单的实现:
- 给
ComplexStructure加一个size_t get_used_memory()方法,手动计算所有容器的预估内存:
size_t ComplexStructure::get_used_memory() const { // map每个节点开销为元素大小+3个指针(红黑树结构),乘以元素数量 size_t s = struct1.size() * (sizeof(std::pair<const AAA, BBB>) + 3 * sizeof(void*)); // vector按容量计算(包含预分配的空闲空间) s += struct2.capacity() * sizeof(CCC); // unordered_map开销为bucket数组大小 + 每个元素的节点开销 s += struct3.bucket_count() * sizeof(void*) + struct3.size() * (sizeof(std::pair<const DDD, EEE>) + sizeof(void*)); return s; }
- 每次调用
generate_some_data/delete_some_data之后,调用这个方法重新计算当前实例的内存,更新到缓冲区的size里即可,改造成本极低。
这类内存配额限制的需求非常常见,多见于缓存系统、嵌入式场景、多租户服务的资源隔离场景,并非你的设计有问题,只是C++标准库没有提供开箱即用的统计分配器,才需要自己手动实现少量逻辑。
内容的提问来源于stack exchange,提问作者algConf
相关产品推荐
相关产品推荐

