我有一个很大的(在运行时固定,约100-3000万)数组数。每个数组的均为0到128个元素,每个元素为6个字节。
我需要将所有数组存储在mmap'ed内存中(所以我不能使用malloc),并且数组需要能够动态生长(最多128个元素,并且阵列永远不会缩小)。
我实现了一种天真的方法,即在mmap'ed内存中具有代表每个块的每个块的状态的int数组。偏移量的0xffffffff值表示MMAP'ED内存中的相应偏移量是免费的,任何其他值是数组的ID(这是我当前实现中块的块中所需的块所需了解其数组的ID以更新其他数据结构)。在分配和数组分配时,它将简单地迭代直到找到足够的自由块,然后在相应的偏移量中插入。
这是分配数组和mmap'ed内存的样子,属于:
| 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)。
这种特定情况有哪些更好的方法?
我对此的理想要求是:
- 内存开销(任何分配表 未使用的空间)< = 1.5位每个元素 4*6字节每个数组
- o(1)阵列的分配和生长
boost.InterProcess似乎对托管内存映射的文件进行了整洁的实现,其规定类似于malloc/free,但对于映射的文件(即,您都有适合大量内存的句柄 - 绘制的文件,您可以要求库将文件的未使用部分分配给某些内容,例如数组)。从文档中:
boost.interprocess提供一些基本类来创建共享内存 对象和文件映射,并将这些映射类映射到 过程的地址空间。
但是,管理这些内存段并不容易 非平凡的任务。映射的区域是固定长度的内存缓冲区, 动态创建和破坏任何类型的对象,需要一个 大量工作,因为它需要编程记忆管理 分配该部分的部分算法。很多时候,我们也 想将名称与共享内存中创建的对象相关联,因此 这些过程可以使用名称找到对象。
boost.interprocess提供4个托管内存段类:
- 管理共享内存映射的区域(basic_managed_shared_memory类)。
- 管理内存映射的文件(basic_managed_mapped_file)。
- 管理分配的堆(运算符新)内存缓冲区(basic_managed_heap_memory类)。
- 管理用户提供的固定尺寸缓冲区(BASIC_MANAGGED_EXTERNAL_BUFFER类)。
托管内存段最重要的服务是:
- 记忆部分的动态分配。
- 在内存段中构造C 对象。这些对象可以是匿名的,也可以将名称与它们相关联。
- 搜索命名对象的功能。
- 自定义许多功能:内存分配算法,索引类型或字符类型。
- 原子结构和破坏,因此,如果两个过程之间共享该段,则不可能创建两个对象 与同名相关联,简化同步。
您可以负担多少个mmap'ed区域?如果128还可以,那么我创建了128个区域,与您的数组的所有可能大小相对应。理想情况下,每个区域的免费条目链接列表。在这种情况下,您将获得每个区域的记录固定尺寸。从n到n 1的数组是将数据从区域[n]移动到末端[n 1]的操作(如果n 1的空条目的链接列表是空的)或空插槽(如果不是)。对于区域[n],删除的插槽被添加到其免费条目列表
更新:链接列表可以嵌入主要结构中。因此,不需要额外的分配,每个可能的记录(从1号到128)内部的第一个字段(int)可能是下一个免费条目的索引。对于分配的条目,它始终是无效的(0xffffffff),但是如果条目是免费的,则该索引成为相应的链接链的成员。
我设计了,最终使用了一种记忆分配算法,该算法几乎满足了我的要求,o(1)摊销,很少的碎片,几乎没有开销。随时发表评论,我有机会时会详细说明。