我有一个非常大的(在运行时修复,大约1000万到3000万)数组。每个数组介于0到128个元素之间,每个元素为6个字节。
我需要将所有数组存储在mmap内存中(因此我不能使用malloc),并且数组需要能够动态增长(最多128个元素,并且数组永远不会缩小)。
我实现了一种简单的方法,即使用一个int数组来表示mmap内存中每个6字节块的状态。偏移处的值0xffffffff表示mmap内存中的相应偏移量是空闲的,任何其他值是数组的id(在我当前实现中对块进行碎片整理时需要,块可以'移动时不知道其数组的id来更新其他数据结构)。在分配时,当数组超出其分配时,它将简单地迭代,直到找到足够的空闲块,并插入相应的偏移量。
分配数组和mmap内存的外观如下:
| 0xffffffff | 0xfffffff | 1234 | 1234 | 0xffffffff | ...
-----------------------------------------------------------------
| free | free |array1234[0]|array1234[1]| free | ...
这种方法的内存开销为offset of furthest used block in mmap'ed memory x 4
(4字节ber int)。
对于这个具体案例,有哪些更好的方法?
我对此的理想要求是:
答案 0 :(得分:1)
Boost.Interprocess似乎有一个简洁的managed memory-mapped files实现,其条款类似于malloc / free但是对于映射文件(即你有一个适当大的内存映射文件的句柄,你可以要求库为文件中的未使用部分进行子分配,例如数组。来自文档:
Boost.Interprocess提供了一些基本类来创建共享内存 对象和文件映射,并将这些可映射的类映射到 进程'地址空间。
但是,管理这些内存段并非易事 非平凡的任务。映射区域是固定长度的内存缓冲区 动态创建和销毁任何类型的对象,需要一个 很多工作,因为它需要编程内存管理 用于分配该段的部分的算法。很多时候,我们也 想要将名称与在共享内存中创建的对象相关联,所以全部 进程可以使用名称找到对象。
Boost.Interprocess提供4个托管内存段类:
- 管理共享内存映射区域(basic_managed_shared_memory类)。
- 管理内存映射文件(basic_managed_mapped_file)。
- 管理堆分配(operator new)内存缓冲区(basic_managed_heap_memory类)。
- 管理用户提供的固定大小缓冲区(basic_managed_external_buffer类)。
托管内存段最重要的服务是:
- 分段内存部分的动态分配。
- 构建内存段中的C ++对象。这些对象可以是匿名的,也可以将名称与它们关联起来。
- 搜索命名对象的功能。
- 自定义许多功能:内存分配算法,索引类型或字符类型。
- 原子构造和析构,以便如果在两个进程之间共享段,则无法创建两个对象 与同名相关联,简化了同步。
答案 1 :(得分:1)
你能承受多少mmap的区域?如果128可以,那么我创建了128个区域,这些区域对应于阵列的所有可能大小。理想情况下,每个区域的免费条目链表。在这种情况下,您将获得每个区域的固定记录大小。并且从N到N + 1生成数组是将数据从区域[N]移动到区域[N + 1]的操作(如果N + 1的空条目的链表是空的)或者是如果不是空槽。对于区域[N],删除的插槽将添加到其空闲条目列表中
更新:链表可以嵌入主结构中。因此,不需要额外的分配,每个可能的记录(从大小1到128)内的第一个字段(int)可以是下一个空闲条目的索引。对于已分配的条目,它始终为void(0xffffffff),但如果条目是空闲的,则此索引将成为相应链接链的成员。
答案 2 :(得分:0)
我设计并最终使用了一个符合我要求的内存分配算法,O(1)摊销,非常少的碎片和非常小的开销。随意评论,我有机会详细说明。