我需要对这个概念进行一些澄清。在内存池上实现。
在wiki上的memory pool,它说
也称为固定大小块分配,..., 因为这些实现因变量而受到碎片的影响 块大小,在实时系统中使用它们是不可能的 由于表现。
“可变块大小如何导致碎片化”如何发生?固定大小的分配如何解决这个问题?这个维基描述对我来说听起来有点误导。我认为通过固定大小的分配或由可变大小引起的碎片不可避免。在内存池上下文中,特定应用程序的特定设计内存分配器可以避免碎片,或者通过限制使用预期的内存块来减少碎片。
同样通过几个实现示例,例如Code Sample 1和Code Sample 2,在我看来,使用内存池,开发人员必须非常了解数据类型,然后剪切,拆分或将数据组织到链接的内存块(如果数据接近链接列表)或分层链接的块(如果数据更加层次化,如文件)。此外,开发人员似乎必须事先预测他需要多少内存。
好吧,我可以想象这适用于一系列原始数据。 C ++非原始数据类怎么样,内存模型不是很明显?即使对于原始数据,开发人员是否应该考虑数据类型对齐?
是否有适合C和C ++的内存池库?
感谢您的任何评论!
答案 0 :(得分:12)
可变块大小确实会导致碎片化。看看我附上的图片:
图像(from here)显示A,B和C分配内存块,可变大小的块的情况。
在某些时候,B释放了所有的内存块,突然间你就会出现碎片。例如,如果C需要分配大量内存,但仍然适合可用内存,则无法做到,因为可用内存分为两个块。
现在,如果你考虑每个内存块大小相同的情况,显然不会出现这种情况。
当然,内存池有其自身的缺点,正如您自己所指出的那样。所以你不应该认为内存池是一个神奇的魔杖。它有成本,在特定情况下支付它是有意义的(即内存有限的嵌入式系统,实时约束等)。
至于哪个内存池在C ++中是好的,我会说它取决于。我在操作系统提供的VxWorks下使用了一个;从某种意义上说,一个好的内存池在与OS紧密集成时是有效的。实际上,我猜每个RTOS都提供了内存池的实现。
如果您正在寻找通用内存池实现,请查看this。
编辑:
从您最后的评论中,在我看来,您可能认为内存池是解决碎片问题的“解决方案”。不幸的是,这种情况并非如此。如果你愿意,碎片是记忆层面熵的表现,即它是不可避免的。另一方面,内存池是一种管理内存的方式,可以有效地减少碎片的影响(正如我所说,并且正如维基百科所提到的,主要是在特定系统上,如实时系统)。这需要付出代价,因为内存池的效率低于“普通”内存分配技术,因为您拥有最小的块大小。换句话说,熵在伪装下重新出现。
此外,这是影响内存池系统效率的许多参数,例如块大小,块分配策略,或者您是否只有一个内存池,或者您有多个具有不同块大小,不同生命周期或不同内存池的内存池政策。
内存管理实际上是一个复杂的问题,内存池只是一种技术,与其他技术一样,与其他技术相比可以改进,并且确定了自己的成本。
答案 1 :(得分:3)
在您总是分配固定大小的块的情况下,您要么有足够的空间再容纳一个块,要么您没有。如果有,则块适合可用空间,因为所有空闲或已用空间的大小相同。碎片不是问题。
在具有可变大小块的方案中,您最终可以使用具有不同大小的多个单独的空闲块。对于大小小于可用总存储空间的块的请求可能无法满足,因为没有一个足够大的连续块。例如,假设您最终得到两个单独的2KB空闲块,并且需要满足3KB的请求。即使有足够的可用内存,这些块都不足以提供它。
答案 2 :(得分:2)
固定大小和可变大小的内存池都具有碎片功能,即在使用过的碎片之间会有一些空闲的内存块。
对于可变大小,这可能会导致问题,因为可能没有足够大的空闲块来满足特定请求的大小。
另一方面,对于固定大小的池,这不是问题,因为只能请求预定义大小的部分。如果有可用空间,则保证足够大(一倍)一部分。
答案 3 :(得分:1)
如果您使用硬实时系统,您可能需要提前知道可以在允许的最长时间内分配内存。这可以通过固定大小的内存池“解决”。
我曾经在军事系统上工作,我们必须计算系统可能使用的每种尺寸的最大可能内存块数。然后将这些数字添加到总计中,系统配置了该内存量。
疯狂昂贵,但为辩护工作。
如果您有多个固定大小的池,即使其他池中有足够的空间,您也可以获得池中没有块的二级碎片。你是如何分享的?
答案 4 :(得分:1)
使用内存池,操作可能会像这样工作:
请注意,对于相同大小的单个数据类型,始终执行此操作;它不适用于较大的那些,然后你可能需要像往常一样使用堆。
实施起来非常容易;我们在申请中使用此策略。这会在程序开始时产生大量内存分配,但不会再发生内存释放/分配,从而导致大量开销。