关于内存池的问题
我需要对概念和概念进行一些澄清。内存池上的实现。
通过 wiki 上的内存池,它说
也称为固定大小块分配,..., 因为这些实现由于变量而遭受碎片化 块大小,不可能在实时系统中使用它们 由于性能。
“可变块大小导致碎片”是如何发生的?固定大小的分配如何解决这个问题?这个维基描述听起来有点误导我。我认为固定大小的分配不能避免碎片,也不能由可变大小引起。在内存池上下文中,通过为特定应用程序专门设计的内存分配器来避免碎片,或者通过限制使用预期的内存块来减少碎片。
另外还有几个实现示例,例如 代码示例 1 和 代码示例2,在我看来,要使用内存池,开发人员必须知道数据类型非常好吧,然后将数据剪切、分割或组织成链接内存块(如果数据接近链接列表)或分层链接块(如果数据组织得更加分层,如文件)。此外,开发人员似乎必须事先预测他需要多少内存。
嗯,我可以想象这对于原始数据数组来说效果很好。那么内存模型不那么明显的 C++ 非原始数据类呢?即使对于原始数据,开发人员是否应该考虑数据类型对齐?
有没有好的 C 和 C++ 内存池库?
感谢您的任何评论!
I need some clarifications for the concept & implementation on memory pool.
By memory pool on wiki, it says that
also called fixed-size-blocks allocation, ... ,
as those implementations suffer from fragmentation because of variable
block sizes, it can be impossible to use them in a real time system
due to performance.
How "variable block size causes fragmentation" happens? How fixed sized allocation can solve this? This wiki description sounds a bit misleading to me. I think fragmentation is not avoided by fixed sized allocation or caused by variable size. In memory pool context, fragmentation is avoided by specific designed memory allocators for specific application, or reduced by restrictly using an intended block of memory.
Also by several implementation samples, e.g., Code Sample 1 and Code Sample 2, it seems to me, to use memory pool, the developer has to know the data type very well, then cut, split, or organize the data into the linked memory chunks (if data is close to linked list) or hierarchical linked chunks (if data is more hierarchical organized, like files). Besides, it seems the developer has to predict in prior how much memory he needs.
Well, I could imagine this works well for an array of primitive data. What about C++ non-primitive data classes, in which the memory model is not that evident? Even for primitive data, should the developer consider the data type alignment?
Is there good memory pool library for C and C++?
Thanks for any comments!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
可变的块大小确实会导致碎片。看看我附加的图片:
图像 (来自此处)显示了 A、B 和 C 分配内存块、可变大小块的情况。
在某个时刻,B 释放了它的所有内存块,突然之间就出现了碎片。例如,如果 C 需要分配一大块内存,但它仍然适合可用内存,则它无法做到这一点,因为可用内存被分成两个块。
现在,如果您考虑每个内存块大小相同的情况,那么这种情况显然不会出现。
当然,正如您自己指出的那样,内存池有其自身的缺点。所以你不应该认为内存池是一根魔杖。它是有成本的,并且在特定情况下(即内存有限、实时限制等的嵌入式系统)支付它是有意义的。
至于C++中哪个内存池好,我想说这要看情况。我在VxWorks下使用了操作系统提供的一个;从某种意义上说,一个好的内存池只有与操作系统紧密结合才有效。我猜实际上每个 RTOS 都提供了内存池的实现。
如果您正在寻找通用内存池实现,请查看此。
编辑:
从您最后的评论来看,在我看来,您可能认为内存池是碎片问题的“解决方案”。不幸的是,事实并非如此。如果你愿意的话,碎片是熵在内存层面的表现,即它是不可避免的。另一方面,内存池是一种管理内存的方法,可以有效减少碎片的影响(正如我所说,正如维基百科提到的,主要是在实时系统等特定系统上)。这是有代价的,因为内存池的效率可能低于“正常”内存分配技术,因为您有最小的块大小。换句话说,熵在伪装下重新出现。
此外,还有许多参数会影响内存池系统的效率,例如块大小、块分配策略,或者您是否只有一个内存池,或者是否有多个具有不同块大小、不同生命周期或不同策略的内存池。
内存管理确实是一个复杂的问题,内存池只是一种技术,与其他技术一样,它比其他技术改进了一些东西,并节省了自己的成本。
Variable block size indeed causes fragmentation. Look at the picture that I am attaching:
The image (from here) shows a situation in which A, B, and C allocates chunks of memory, variable sized chunks.
At some point, B frees all its chunks of memory, and suddenly you have fragmentation. E.g., if C needed to allocate a large chunk of memory, that still would fit into available memory, it could not do because available memory is split in two blocks.
Now, if you think about the case where each chunk of memory would be of the same size, this situation would clearly not arise.
Memory pools, of course, have their own drawbacks, as you yourself point out. So you should not think that a memory pool is a magical wand. It has a cost and it makes sense to pay it under specific circumstances (i.e., embedded system with limited memory, real time constraints and so on).
As to which memory pool is good in C++, I would say that it depends. I have used one under VxWorks that was provided by the OS; in a sense, a good memory pool is effective when it is tightly integrated with the OS. Actually each RTOS offers an implementation of memory pools, I guess.
If you are looking for a generic memory pool implementation, look at this.
EDIT:
From you last comment, it seems to me that possibly you are thinking of memory pools as "the" solution to the problem of fragmentation. Unfortunately, this is not the case. If you want, fragmentation is the manifestation of entropy at the memory level, i.e., it is inevitable. On the other hand, memory pools are a way to manage memory in such a way as to effectively reduce the impact of fragmentation (as I said, and as wikipedia mentioned, mostly on specific systems like real time systems). This comes to a cost, since a memory pool can be less efficient than a "normal" memory allocation technique in that you have a minimum block size. In other words, the entropy reappears under disguise.
Furthermore, that are many parameters that affect the efficiency of a memory pool system, like block size, block allocation policy, or whether you have just one memory pool or you have several memory pools with different block sizes, different lifetimes or different policies.
Memory management is really a complex matter and memory pools are just a technique that, like any other, improves things in comparison to other techniques and exact a cost of its own.
在您始终分配固定大小块的情况下,您要么有足够的空间再容纳一个块,要么没有。如果有,则该块适合可用空间,因为所有可用或已用空间的大小相同。碎片不是问题。
在具有可变大小块的场景中,您最终可能会得到多个不同大小的独立空闲块。对大小小于可用内存总量的块的请求可能无法满足,因为没有一个足够大的连续块。例如,假设您最终有两个独立的 2KB 空闲块,并且需要满足 3KB 的请求。即使有足够的可用内存,这些块都不足以满足这一要求。
In a scenario where you always allocate fixed-size blocks, you either have enough space for one more block, or you don't. If you have, the block fits in the available space, because all free or used spaces are of the same size. Fragmentation is not a problem.
In a scenario with variable-size blocks, you can end up with multiple separate free blocks with varying sizes. A request for a block of a size that is less than the total memory that is free may be impossible to be satisfied, because there isn't one contiguous block big enough for it. For example, imagine you end up with two separate free blocks of 2KB, and need to satisfy a request for 3KB. Neither of these blocks will be enough to provide for that, even though there is enough memory available.
固定大小和可变大小的内存池都具有碎片的特点,即在已使用的内存块之间会有一些空闲内存块。
对于可变大小,这可能会导致问题,因为可能没有足够大的空闲块来满足特定请求的大小。
另一方面,对于固定大小的池,这不是问题,因为只能请求预定义大小的部分。如果有可用空间,则保证足够大以容纳一份(的倍数)。
Both fix-size and variable size memory pools will feature fragmentation, i.e. there will be some free memory chunks between used ones.
For variable size, this might cause problems, since there might not be a free chunk that is big enough for a certain requested size.
For fixed-size pools, on the other hand, this is not a problem, since only portions of the pre-defined size can be requested. If there is free space, it is guaranteed to be large enough for (a multiple of) one portion.
如果你做一个硬实时系统,你可能需要提前知道你可以在允许的最大时间内分配内存。这可以通过固定大小的内存池来“解决”。
我曾经在一个军事系统上工作过,我们必须计算系统可能使用的每种大小的内存块的最大可能数量。然后将这些数字添加到总计中,并为系统配置了该数量的内存。
贵得离谱,但对防守有用。
当您有多个固定大小的池时,即使其他池中有足够的空间,您的池也会出现块不足的情况,从而导致二级碎片。你如何分享?
If you do a hard real time system, you might need to know in advance that you can allocate memory within the maximum time allowed. That can be "solved" with fixed size memory pools.
I once worked on a military system, where we had to calculate the maximum possible number of memory blocks of each size that the system could ever possibly use. Then those numbers were added to a grand total, and the system was configured with that amount of memory.
Crazily expensive, but worked for the defence.
When you have several fixed size pools, you can get a secondary fragmentation where your pool is out of blocks even though there is plenty of space in some other pool. How do you share that?
使用内存池,操作可能会像这样工作:
请注意,这始终是针对相同大小的单个数据类型完成的;它不适用于较大的堆,然后您可能需要像往常一样使用堆。
它非常容易实现;我们在我们的应用程序中使用这个策略。这会导致在程序开始时进行大量内存分配,但不会再发生内存释放/分配,从而产生大量开销。
With a memory pool, operations might work like this:
Note that this is always done for a single data type of the same size; it doesn't work for larger ones and then you probably need to use the heap as usual.
It's very easy to implement; we use this strategy in our application. This causes a bunch of memory allocations at the beginning of the program, but no more memory freeing/allocating occurs which incurs significant overhead.