在内存池中查找下一个可用区块
Find next available chunk in a memory pool
所以,我花了一些时间在C++中实现了一个内存池类。除了一些小问题外,一切都很顺利。然而,当我今天尝试通过首先使用内存池分配1000个块,然后将其与使用new进行比较来测试它时,实际上我在使用内存池时的性能差了三倍(以纳秒为单位)。我的分配方法如下:
template <class T> T* MemPool<T>::allocate()
{
Chunk<T>* tempChunk = _startChunk;
while (tempChunk->_free == false)
{
if (tempChunk->_nextChunk == NULL)
throw std::runtime_error("No available chunks");
tempChunk = tempChunk->_nextChunk;
}
tempChunk->_free = false;
return &tempChunk->object;
}
我从池中的第一个区块开始,在池的链表中进行搜索,直到找到可用区块,或者到达池的末尾。现在,池越大,所需时间就越长,因为搜索的时间复杂度为O(n),其中n是池中块的数量。
所以我很好奇,有没有人对如何改善分配有什么想法?我最初的想法是使用两个链表,而不是只使用一个,其中一个包含空闲块,另一个包含分配的块。当要分配一个新的区块时,我只需取第一个提到的链表中的第一个元素,并将其移动到分配的链表中。据我所见,这将消除在分配时进行任何搜索的需要,只留下需要搜索才能找到正确块的释放。
任何想法都会受到赞赏,因为这是我第一次以这种方式直接与记忆打交道。谢谢
与其使用手工编制的链表,不如使用std::list
(尤其是与自定义分配器一起使用)。不易出错,而且可能优化得更好。
使用两个列表可以简化很多。无需在列表本身中跟踪区块是否空闲,因为这将由区块所在的列表指定(所需的只是确保区块不会以某种方式出现在两个列表中)。
您当前的实现意味着您在分配和解除分配时都必须遍历链表。
如果区块大小固定,那么只需将第一个可用区块从空闲列表移动到已分配列表即可实现分配,无需搜索。要解除分配区块,您仍然需要在分配的列表中找到它,这意味着您需要将T*
映射到列表中的条目(例如,执行搜索),但解除分配的行为只是将条目从一个列表移动到另一个列表。
如果区块大小可变,则需要做更多的工作。分配需要在分配时找到一个至少为请求大小的块。过度分配(分配比需要的更大的块)会使分配和释放在性能方面更高效,但也意味着可以从池中分配更少的块。或者,将一大块(从空闲列表中)一分为二,并在两个列表上放置一个条目(表示已分配的部分和未分配的部分)。如果这样做,在解除分配时,可能需要合并内存中相邻的块(有效地,对池中的可用内存进行碎片整理)。
您需要决定是否可以从多个线程使用池,并使用适当的同步。
使用固定数量的大小bin,并使每个bin成为一个链表。
例如,假设您的bin只是系统页面大小(通常为4KiB)的整数倍,并且您使用1MiB块;则您有1MiB/4KiB=256个仓。如果free使块中的n页区域可用,则将其附加到bin n。在分配n页区域时,遍历从n到256的bin并选择第一个可用块。
为了最大限度地提高性能,请将bin与位图相关联,然后从第n-1位扫描到第255位以找到第一个设置位(使用编译器内部函数(如__builtin_clz和_BitScanForward)计算前导或尾随零)。由于垃圾箱的数量,这仍然不完全是O(1),但它非常接近。
如果你担心内存开销,你可以为每个bin只附加一次每个chunk。也就是说,即使块具有128个可用的1页区域(最大程度地分段),仓1仍将仅链接到该块一次并重用它128次。
要做到这一点,你必须在每个区块内将这些区域链接在一起,这意味着每个区块还需要存储一个大小仓的列表,但这可以提高内存效率,因为每个区块内最多只有256个有效偏移,而列表需要存储完整的指针。
请注意,无论哪种方式,如果你不想让每个区块内的可用空间变得碎片化,你都需要一种快速的方法来从列表中的垃圾箱中删除区块,这意味着使用双链接列表。显然,这会增加额外的内存开销,但它可能仍然比对整个列表进行定期的可用空间碎片整理更可取。
- 重新定位图像时如何前进到下一个内存块
- 为什么C++对链表中的下一个节点使用指针,而像 C# 或 Java 这样的语言只使用类 Node 的名称?
- 用于在 C++ 中使用 while 循环查找下一个素数的简单函数
- CIN 仅在输入非数字值时跳过下一个 CIN
- 查找最小的下一个更大的元素
- 转到基于范围的 for 循环中的下一个迭代器
- 如何检查流中文件的下一个单词是否为 alpha?
- 如何打印下一个字母直到 Z 并继续到 A?
- 在使用堆栈为下一个最大数字编写代码时面临 SIGSEGV(分段错误)
- 你能用 c++ 做一个指向类的指针吗?
- 使用一个内存集数组和单个堆栈在 O(n) 中查找数组的下一个更大元素
- 有没有一种标准方法可以在C++中获取第 n 个"下一个"浮点值
- 下一个云桌面客户端构建过程
- C++自定义流操纵器,用于更改流上的下一个字符串
- 链表指针赋值为什么我们不能直接将尾巴分配给 temp 而不是尾巴>尾巴下一个
- 下一个排列定义
- 查找下一个具有真值C++的数组索引
- 如何比较文件中包含的下一个字符
- 用下一个最大的元素替换每个元素?
- 如何在Windows下用c++代码创建一个新进程