C++ 什么是内存碎片?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3770457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:40:02  来源:igfitidea点击:

What is memory fragmentation?

c++memoryheapfragmentation

提问by AshleysBrain

I've heard the term "memory fragmentation" used a few times in the context of C++ dynamic memory allocation. I've found some questions about how to deal with memory fragmentation, but can't find a direct question that deals with it itself. So:

我听说过在 C++ 动态内存分配的上下文中使用过几次“内存碎片”这个术语。我发现了一些关于如何处理内存碎片的问题,但找不到直接处理它本身的问题。所以:

  • What is memory fragmentation?
  • How can I tell if memory fragmentation is a problem for my application? What kind of program is most likely to suffer?
  • What are good common ways to deal with memory fragmentation?
  • 什么是内存碎片?
  • 如何判断内存碎片是否是我的应用程序的问题?什么样的程序最容易受到影响?
  • 处理内存碎片的常用方法有哪些?

Also:

还:

  • I've heard using dynamic allocations a lot can increase memory fragmentation. Is this true? In the context of C++, I understand all the standard containers (std::string, std::vector, etc) use dynamic memory allocation. If these are used throughout a program (especially std::string), is memory fragmentation more likely to be a problem?
  • How can memory fragmentation be dealt with in an STL-heavy application?
  • 我听说经常使用动态分配会增加内存碎片。这是真的?在 C++ 的上下文中,我了解所有标准容器(std::string、std::vector 等)都使用动态内存分配。如果这些在整个程序中使用(尤其是 std::string),内存碎片是否更有可能成为问题?
  • 如何在 STL 密集型应用程序中处理内存碎片?

回答by Steve Jessop

Imagine that you have a "large" (32 bytes) expanse of free memory:

想象一下,您有一个“大”(32 字节)的空闲内存空间:

----------------------------------
|                                |
----------------------------------

Now, allocate some of it (5 allocations):

现在,分配其中的一部分(5 次分配):

----------------------------------
|aaaabbccccccddeeee              |
----------------------------------

Now, free the first four allocations but not the fifth:

现在,释放前四个分配而不是第五个:

----------------------------------
|              eeee              |
----------------------------------

Now, try to allocate 16 bytes. Oops, I can't, even though there's nearly double that much free.

现在,尝试分配 16 个字节。哎呀,我不能,即使有几乎两倍的免费。

On systems with virtual memory, fragmentation is less of a problem than you might think, because large allocations only need to be contiguous in virtualaddress space, not in physicaladdress space. So in my example, if I had virtual memory with a page size of 2 bytes then I could make my 16 byte allocation with no problem. Physical memory would look like this:

在具有虚拟内存的系统上,碎片问题比您想象的要少,因为大分配只需要在虚拟地址空间中连续,而不是在物理地址空间中。所以在我的例子中,如果我有一个页面大小为 2 字节的虚拟内存,那么我可以毫无问题地进行 16 字节的分配。物理内存看起来像这样:

----------------------------------
|ffffffffffffffeeeeff            |
----------------------------------

whereas virtual memory (being much bigger) could look like this:

而虚拟内存(更大)可能如下所示:

------------------------------------------------------...
|              eeeeffffffffffffffff                   
------------------------------------------------------...

The classic symptom of memory fragmentation is that you try to allocate a large block and you can't, even though you appear to have enough memory free. Another possible consequence is the inability of the process to release memory back to the OS (because there's some object still in use in all the blocks it has allocated from the OS, even though those blocks are now mostly unused).

内存碎片的典型症状是你试图分配一个大块,但你不能,即使你似乎有足够的可用内存。另一个可能的后果是进程无法将内存释放回操作系统(因为在它从操作系统分配的所有块中仍有一些对象在使用,即使这些块现在大部分未使用)。

Tactics to prevent memory fragmentation in C++ work by allocating objects from different areas according to their size and/or their expected lifetime. So if you're going to create a lot of objects and destroy them all together later, allocate them from a memory pool. Any other allocations you do in between them won't be from the pool, hence won't be located in between them in memory, so memory will not be fragmented as a result.

通过根据对象的大小和/或预期寿命从不同区域分配对象来防止 C++ 中的内存碎片的策略。因此,如果您要创建大量对象并稍后将它们全部销毁,请从内存池中分配它们。您在它们之间进行的任何其他分配都不会来自池,因此不会位于它们之间的内存中,因此内存不会因此而碎片化。

Generally you don't need to worry about it much, unless your program is long-running and does a lot of allocation and freeing. It's when you have mixtures of short-lived and long-lived objects that you're most at risk, but even then mallocwill do its best to help. Basically, ignore it until your program has allocation failures or unexpectedly causes the system to run low on memory (catch this in testing, for preference!).

一般来说,你不需要太担心,除非你的程序是长时间运行的,并且做了大量的分配和释放。当您同时拥有短期和长期存在的物体时,您的风险最大,但即便如此,您malloc也会尽力提供帮助。基本上,在您的程序出现分配失败或意外导致系统内存不足之前忽略它(在测试中捕获它,优先考虑!)。

The standard libraries are no worse than anything else that allocates memory, and standard containers all have an Alloctemplate parameter which you could use to fine-tune their allocation strategy if absolutely necessary.

标准库并不比分配内存的任何其他东西差,标准容器都有一个Alloc模板参数,如果绝对必要,您可以使用它来微调它们的分配策略。

回答by Mike Dinescu

What is memory fragmentation?

什么是内存碎片?

Memory fragmentation is when most of your memory is allocated in a large number of non-contiguous blocks, or chunks - leaving a good percentage of your total memory unallocated, but unusable for most typical scenarios. This results in out of memory exceptions, or allocation errors (i.e. malloc returns null).

内存碎片是指您的大部分内存分配在大量不连续的块或块中 - 总内存中有很大一部分未分配,但在大多数典型情况下无法使用。这会导致内存不足异常或分配错误(即 malloc 返回 null)。

The easiest way to think about this is to imagine you have a big empty wall that you need to put pictures of varying sizeson. Each picture takes up a certain size and you obviously can't split it into smaller pieces to make it fit. You need an empty spot on the wall, the size of the picture, or else you can't put it up. Now, if you start hanging pictures on the wall and you're not careful about how you arrange them, you will soon end up with a wall that's partially covered with pictures and even though you may have empty spots most new pictures won't fit because they're larger than the available spots. You can still hang really small pictures, but most ones won't fit. So you'll have to re-arrange (compact) the ones already on the wall to make room for more..

考虑这个问题的最简单方法是想象你有一个大的空墙,你需要在上面放不同尺寸的照片。每张图片都占用一定的大小,显然您无法将其分成更小的部分以使其适合。你需要在墙上有一个空位,图片的大小,否则你放不下。现在,如果您开始将图片挂在墙上并且不注意如何排列它们,您很快就会得到一面部分被图片覆盖的墙,即使您可能有空的地方,大多数新图片也不适合因为它们比可用的点大。你仍然可以挂非常小的图片,但大多数不适合。因此,您必须重新排列(压缩)墙上已有的那些,以腾出更多空间。

Now, imagine that the wall is your (heap) memory and the pictures are objects.. That's memory fragmentation..

现在,想象墙是你的(堆)内存,图片是对象..那是内存碎片..

How can I tell if memory fragmentation is a problem for my application? What kind of program is most likely to suffer?

如何判断内存碎片是否是我的应用程序的问题?什么样的程序最容易受到影响?

A telltale sign that you may be dealing with memory fragmentation is if you get many allocation errors, especially when the percentage of used memory is high - but not you haven't yet used up all the memory - so technically you should have plenty of room for the objects you are trying to allocate.

您可能正在处理内存碎片的一个明显迹象是,如果您遇到许多分配错误,尤其是当已用内存的百分比很高时 - 但您还没有用完所有内存 - 所以从技术上讲,您应该有足够的空间对于您尝试分配的对象。

When memory is heavily fragmented, memory allocations will likely take longer because the memory allocator has to do more work to find a suitable space for the new object. If in turn you have many memory allocations (which you probably do since you ended up with memory fragmentation) the allocation time may even cause noticeable delays.

当内存严重碎片化时,内存分配可能需要更长的时间,因为内存分配器必须做更多的工作来为新对象找到合适的空间。如果反过来你有很多内存分配(你可能会因为你最终出现内存碎片而这样做)分配时间甚至可能导致明显的延迟。

What are good common ways to deal with memory fragmentation?

处理内存碎片的常用方法有哪些?

Use a good algorithm for allocating memory. Instead of allocating memory for a lot of small objects, pre-allocate memory for a contiguous array of those smaller objects. Sometimes being a little wasteful when allocating memory can go along way for performance and may save you the trouble of having to deal with memory fragmentation.

使用一个好的算法来分配内存。不是为许多小对象分配内存,而是为这些小对象的连续数组预先分配内存。有时在分配内存时有点浪费可以提高性能,并且可以省去处理内存碎片的麻烦。

回答by Tyler McHenry

Memory fragmentation is the same concept as disk fragmentation: it refers to space being wasted because the areas in use are not packed closely enough together.

内存碎片与磁盘碎片的概念相同:它指的是由于使用的区域没有足够紧密地组合在一起而浪费的空间。

Suppose for a simple toy example that you have ten bytes of memory:

假设有一个简单的玩具示例,您有十个字节的内存:

 |   |   |   |   |   |   |   |   |   |   |
   0   1   2   3   4   5   6   7   8   9

Now let's allocate three three-byte blocks, name A, B, and C:

现在让我们分配三个三字节的块,名称为 A、B 和 C:

 | A | A | A | B | B | B | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

Now deallocate block B:

现在释放块 B:

 | A | A | A |   |   |   | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

Now what happens if we try to allocate a four-byte block D? Well, we have four bytes of memory free, but we don't have four contiguousbytes of memory free, so we can't allocate D! This is inefficient use of memory, because we should have been able to store D, but we were unable to. And we can't move C to make room, because very likely some variables in our program are pointing at C, and we can't automatically find and change all of these values.

现在如果我们尝试分配一个四字节的块 D 会发生什么?好吧,我们有四个字节的内存可用,但是我们没有四个连续的可用内存字节,所以我们不能分配 D!这是内存的低效使用,因为我们应该能够存储 D,但我们不能。我们不能移动 C 来腾出空间,因为很可能我们程序中的一些变量指向 C,我们无法自动查找和更改所有这些值。

How do you know it's a problem? Well, the biggest sign is that your program's virtual memory size is considerably larger than the amount of memory you're actually using. In a real-world example, you would have many more than ten bytes of memory, so D would just get allocated starting a byte 9, and bytes 3-5 would remain unused unless you later allocated something three bytes long or smaller.

你怎么知道有问题?嗯,最大的迹象是你的程序的虚拟内存大小远远大于你实际使用的内存量。在实际示例中,您将拥有超过 10 个字节的内存,因此 D 将仅从字节 9 开始分配,而字节 3-5 将保持未使用状态,除非您稍后分配了三个字节或更小的内存。

In this example, 3 bytes is not a whole lot to waste, but consider a more pathological case where two allocations of a a couple of bytes are, for example, ten megabytes apart in memory, and you need to allocate a block of size 10 megabytes + 1 byte. You have to go ask the OS for over ten megabytes more virtual memory to do that, even though you're just one byte shy of having enough space already.

在这个例子中,3 个字节并不是很多可以浪费的,但是考虑一个更病态的情况,其中两个字节的两次分配在内存中相距 10 兆字节,而您需要分配一个大小为 10 兆字节的块+ 1 个字节。您必须向操作系统请求多出 10 兆字节以上的虚拟内存才能做到这一点,即使您已经拥有足够的空间仅差 1 个字节。

How do you prevent it? The worst cases tend to arise when you frequently create and destroy small objects, since that tends to produce a "swiss cheese" effect with many small objects separated by many small holes, making it impossible to allocate larger objects in those holes. When you know you're going to be doing this, an effective strategy is to pre-allocate a large block of memory as a pool for your small objects, and then manually manage the creation of the small objects within that block, rather than letting the default allocator handle it.

你如何预防?当您经常创建和销毁小对象时,往往会出现最坏的情况,因为这往往会产生“瑞士奶酪”效应,许多小对象被许多小孔隔开,从而无法在这些孔中分配较大的对象。当你知道你要这样做时,一个有效的策略是预先分配一大块内存作为小对象的池,然后手动管理该块内小对象的创建,而不是让默认分配器处理它。

In general, the fewer allocations you do, the less likely memory is to get fragmented. However, STL deals with this rather effectively. If you have a string which is using the entirety of its current allocation and you append one character to it, it doesn't simply re-allocate to its current length plus one, it doublesits length. This is a variation on the "pool for frequent small allocations" strategy. The string is grabbing a large chunk of memory so that it can deal efficiently with repeated small increases in size without doing repeated small reallocations. All STL containers in fact do this sort of thing, so generally you won't need to worry too much about fragmentation caused by automatically-reallocating STL containers.

通常,您分配的内存越少,内存碎片化的可能性就越小。然而,STL 相当有效地处理了这个问题。如果您有一个字符串,它正在使用其当前分配的全部内容,并且您向其附加一个字符,则它不会简单地重新分配为其当前长度加一,而是将其长度加倍。这是“频繁小分配池”策略的变体。该字符串正在占用一大块内存,以便它可以有效地处理重复的小规模增长,而无需进行重复的小规模重新分配。实际上所有的STL 容器都做这种事情,所以一般你不需要太担心自动重新分配STL 容器造成的碎片。

Although of course STL containers don't pool memory betweeneach other, so if you're going to create many small containers (rather than a few containers that get resized frequently) you may have to concern yourself with preventing fragmentation in the same way you would for any frequently-created small objects, STL or not.

尽管 STL 容器当然不会彼此之间共享内存,因此如果您要创建许多小容器(而不是一些经常调整大小的容器),您可能必须像您一样关注防止碎片化将用于任何经常创建的小对象,无论是否使用 STL。

回答by Michael Borgwardt

  • What is memory fragmentation?
  • 什么是内存碎片?

Memory fragmentation is the problem of memory becoming unusable even though it is theoretically available. There are two kinds of fragmentation: internal fragmentationis memory that is allocated but cannot be used (e.g. when memory is allocated in 8 byte chunks but the program repeatedly does single allications when it needs only 4 bytes). external fragmentationis the problem of free memory becoming divided into many small chunks so that large allocation requests cannot be met although there is enough overall free memory.

内存碎片是内存变得不可用的问题,即使它在理论上可用。有两种碎片:内部碎片是分配了但不能使用的内存(例如,当内存以8字节块分配时,但程序只需要4个字节时重复进行单个分配)。外部碎片是空闲内存被分成许多小块的问题,这样即使有足够的整体空闲内存,也无法满足大的分配请求。

  • How can I tell if memory fragmentation is a problem for my application? What kind of program is most likely to suffer?
  • 如何判断内存碎片是否是我的应用程序的问题?什么样的程序最容易受到影响?

memory fragmentation is a problem if your program uses much more system memory than its actual paylod data would require (and you've ruled out memory leaks).

如果您的程序使用的系统内存比其实际有效载荷数据所需的多得多(并且您已经排除了内存泄漏),那么内存碎片就是一个问题。

  • What are good common ways to deal with memory fragmentation?
  • 处理内存碎片的常用方法有哪些?

Use a good memory allocator. IIRC, those that use a "best fit" strategy are generally much superior at avoiding fragmentation, if a little slower. However, it has also been shown that for any allocation strategy, there are pathological worst cases. Fortunately, the typical allocation patterns of most applications are actually relatively benign for the allocators to handle. There's a bunch of papers out there if you're interested in the details:

使用一个好的内存分配器。IIRC,那些使用“最适合”策略的人通常在避免碎片化方面要好得多,如果稍微慢一点。然而,也已经表明,对于任何分配策略,都有病态的最坏情况。幸运的是,大多数应用程序的典型分配模式实际上对于分配器处理来说是相对温和的。如果你对细节感兴趣,这里有很多论文:

  • Paul R. Wilson, Mark S. Johnstone, Michael Neely and David Boles. Dynamic Storage Allocation: A Survey and Critical Review. In Proceedings of the 1995 International Workshop on Memory Management, Springer Verlag LNCS, 1995
  • Mark S.Johnstone, Paul R. Wilson. The Memory Fragmentation Problem: Solved? In ACM SIG-PLAN Notices, volume 34 No. 3, pages 26-36, 1999
  • M.R. Garey, R.L. Graham and J.D. Ullman. Worst-Case analysis of memory allocation algorithms. In Fourth Annual ACM Symposium on the Theory of Computing, 1972
  • Paul R. Wilson、Mark S. Johnstone、Michael Neely 和 David Boles。动态存储分配:调查和批判性。In Proceedings of the 1995 International Workshop on Memory Management, Springer Verlag LNCS, 1995
  • 马克 S.约翰斯通,保罗 R. 威尔逊。内存碎片问题:解决了吗?在 ACM SIG-PLAN Notices, volume 34 No. 3, pages 26-36, 1999
  • 加里先生、RL 格雷厄姆和 JD 厄尔曼。内存分配算法的最坏情况分析。1972 年第四届 ACM 计算理论年会

回答by Michael Borgwardt

Update:
Google TCMalloc: Thread-Caching Malloc
It has been found that it is quite good at handling fragmentationin a long running process.

更新:
谷歌 TCMalloc:线程缓存 Malloc
已经发现它非常擅长处理长时间运行的进程中的碎片



I have been developing a server application that had problems with memory fragmentation on HP-UX 11.23/11.31 ia64.

我一直在开发一个服务器应用程序,该应用程序在 HP-UX 11.23/11.31 ia64 上存在内存碎片问题。

It looked like this. There was a process that made memory allocations and deallocations and ran for days. And even though there were no memory leaks memory consumption of the process kept increasing.

它看起来像这样。有一个进程进行内存分配和释放并运行了数天。即使没有内存泄漏,进程的内存消耗也在不断增加。

About my experience. On HP-UX it is very easy to find memory fragmentation using HP-UX gdb. You set a break-point and when you hit it you run this command: info heapand see all memory allocations for the process and the total size of heap. Then your continue your program and then some time later your again hit the break-point. You do again info heap. If the total size of heap is bigger but the number and the size of separate allocations are the same then it is likely that you have memory allocation problems. If necessary do this check few fore times.

关于我的经历。在 HP-UX 上,使用 HP-UX gdb 很容易找到内存碎片。你设置一个断点,当你点击它时,你运行这个命令:info heap并查看进程的所有内存分配和堆的总大小。然后你继续你的程序,然后一段时间后你再次遇到断点。你再做一次info heap。如果堆的总大小较大,但单独分配的数量和大小相同,则可能存在内存分配问题。如有必要,请先检查几次。

My way of improving the situation was this. After I had done some analysis with HP-UX gdb I saw that memory problems were caused by the fact that I used std::vectorfor storing some types of information from a database. std::vectorrequires that its data must be kept in one block. I had a few containers based on std::vector. These containers were regularly recreated. There were often situations when new records were added to the database and after that the containers were recreated. And since the recreated containers were bigger their did not fit into available blocks of free memory and the runtime asked for a new bigger block from the OS. As a result even though there were no memory leaks the memory consumption of the process grew. I improved the situation when I changed the containers. Instead of std::vectorI started using std::dequewhich has a different way of allocating memory for data.

我改善这种情况的方法是这样的。在我对 HP-UX gdb 进行了一些分析之后,我发现内存问题是由我用于std::vector存储来自数据库的某些类型的信息这一事实引起的。std::vector要求其数据必须保存在一个块中。我有几个基于std::vector. 这些容器会定期重新创建。经常会出现将新记录添加到数据库然后重新创建容器的情况。而且由于重新创建的容器更大,它们不适合可用的可用内存块,并且运行时要求操作系统提供一个新的更大的块。结果,即使没有内存泄漏,进程的内存消耗也会增加。当我更换容器时,我的情况有所改善。而不是std::vector我开始使用std::deque它有一种为数据分配内存的不同方式。

I know that one of ways to avoid memory fragmentation on HP-UX is to use either Small Block Allocator or use MallocNextGen. On RedHat Linux the default allocator seems to handle pretty well allocating of a lot of small blocks. On Windows there is Low-fragmentation Heapand it adresses the problem of large number of small allocations.

我知道在 HP-UX 上避免内存碎片的方法之一是使用 Small Block Allocator 或使用 MallocNextGen。在 RedHat Linux 上,默认分配器似乎可以很好地处理大量小块的分配。在 Windows 上Low-fragmentation Heap,它解决了大量小分配的问题。

My understanding is that in an STL-heavy application you have first to identify problems. Memory allocators (like in libc) actually handle the problem of a lot of small allocations, which is typical for std::string(for instance in my server application there are lots of STL strings but as I see from running info heapthey are not causing any problems). My impression is that you need to avoid frequent large allocations. Unfortunately there are situations when you can't avoid them and have to change your code. As I say in my case I improved the situation when switched to std::deque. If you identify your memory fragmention it might be possible to talk about it more precisely.

我的理解是,在 STL 密集型应用程序中,您必须首先识别问题。内存分配器(如在 libc 中)实际上处理了很多小分配的问题,这是典型的std::string(例如在我的服务器应用程序中有很多 STL 字符串,但我从运行中看到info heap它们没有引起任何问题)。我的印象是你需要避免频繁的大分配。不幸的是,在某些情况下您无法避免它们并且必须更改您的代码。正如我在我的情况下所说的那样,我在切换到std::deque. 如果您确定您的内存碎片,则可能更准确地谈论它。

回答by Stephen Kellett

A very detailed answer on memory fragmentation can be found here.

可以在此处找到有关内存碎片的非常详细的答案。

http://library.softwareverify.com/memory-fragmentation-your-worst-nightmare/

http://library.softwareverify.com/memory-fragmentation-your-worst-nightmare/

This is the culmination of 11 years of memory fragmentation answers I have been providing to people asking me questions about memory fragmentation at softwareverify.com

这是 11 年来我一直在为在 softwareverify.com 上向我询问有关内存碎片问题的人们提供的内存碎片答案的高潮

回答by Bj?rn Pollex

Memory fragmentation is most likely to occur when you allocate and deallocatemany objects of varying sizes. Suppose you have the following layout in memory:

当您分配和释放许多不同大小的对象时,最有可能发生内存碎片。假设您在内存中有以下布局:

obj1 (10kb) | obj2(20kb) | obj3(5kb) | unused space (100kb)

Now, when obj2is released, you have 120kb of unused memory, but you cannot allocate a full block of 120kb, because the memory is fragmented.

现在,当obj2被释放时,您有 120kb 未使用的内存,但您无法分配 120kb 的完整块,因为内存是碎片化的。

Common techniques to avoid that effect include ring buffersand object pools. In the context of the STL, methods like std::vector::reserve()can help.

避免这种影响的常用技术包括环形缓冲区对象池。在 STL 的上下文中,像这样的方法std::vector::reserve()可以提供帮助。

回答by Péter T?r?k

What is memory fragmentation?

什么是内存碎片?

When your app uses dynamic memory, it allocates and frees chunks of memory. In the beginning, the whole memory space of your app is one contiguous block of free memory. However, when you allocate and free blocks of different size, the memory starts to get fragmented, i.e. instead of a big contiguous free block and a number of contiguous allocated blocks, there will be a allocated and free blocks mixed up. Since the free blocks have limited size, it is difficult to reuse them. E.g. you may have 1000 bytes of free memory, but can't allocate memory for a 100 byte block, because all the free blocks are at most 50 bytes long.

当您的应用程序使用动态内存时,它会分配和释放内存块。一开始,你的应用程序的整个内存空间是一个连续的空闲内存块。然而,当你分配和释放不同大小的块时,内存开始变得碎片化,即不是一个大的连续空闲块和许多连续的分配块,而是一个已分配和空闲块混合在一起。由于空闲块的大小有限,因此很难重用它们。例如,您可能有 1000 字节的空闲内存,但不能为 100 字节的块分配内存,因为所有空闲块的长度最多为 50 字节。

Another, unavoidable, but less problematic source of fragmentation is that in most architectures, memory addresses must be alignedto 2, 4, 8 etc. byte boundaries (i.e. the addresses must be multiples of 2, 4, 8 etc.) This means that even if you have e.g. a struct containing 3 charfields, your struct may have a size of 12 instead of 3, due to the fact that each field is aligned to a 4-byte boundary.

另一个不可避免但问题较少的碎片来源是,在大多数体系结构中,内存地址必须2、4、8 等字节边界对齐(即地址必须是 2、4、8 等的倍数)。这意味着即使您有一个包含 3 个char字段的结构体,您的结构体的大小也可能是 12 而不是 3,因为每个字段都与 4 字节边界对齐。

How can I tell if memory fragmentation is a problem for my application? What kind of program is most likely to suffer?

如何判断内存碎片是否是我的应用程序的问题?什么样的程序最容易受到影响?

The obvious answer is that you get an out of memory exception.

显而易见的答案是您会遇到内存不足异常。

Apparently there is no good portable way to detect memory fragmentation in C++ apps. See this answerfor more details.

显然,在 C++ 应用程序中没有检测内存碎片的好方法。有关更多详细信息,请参阅此答案

What are good common ways to deal with memory fragmentation?

处理内存碎片的常用方法有哪些?

It is difficult in C++, since you use direct memory addresses in pointers, and you have no control over who references a specific memory address. So rearranging the allocated memory blocks (the way the Java garbage collector does) is not an option.

这在 C++ 中很困难,因为您在指针中使用直接内存地址,并且您无法控制谁引用了特定的内存地址。因此,重新排列分配的内存块(Java 垃圾收集器所做的方式)不是一种选择。

A custom allocator may help by managing the allocation of small objects in a bigger chunk of memory, and reusing the free slots within that chunk.

自定义分配器可以帮助管理更大内存块中小对象的分配,并重用该块中的空闲插槽。

回答by user455288

This is a super-simplified version for dummies.

这是傻瓜的超级简化版本。

As objects get created in memory, they get added to the end of the used portion in memory.

当对象在内存中创建时,它们会被添加到内存中使用部分的末尾。

If an object that is not at the end of the used portion of memory is deleted, meaning this object was in between 2 other objects, it will create a "hole".

如果一个不在内存已用部分末尾的对象被删除,这意味着该对象位于其他 2 个对象之间,它将创建一个“洞”。

This is what's called fragmentation.

这就是所谓的碎片化。

回答by wheaties

When you want to add an item on the heap what happens is that the computer has to do a search for space to fit that item. That's why dynamic allocations when not done on a memory pool or with a pooled allocator can "slow" things down. For a heavy STL application if you're doing multi-threading there is the Hoard allocatoror the TBB Intelversion.

当您想在堆上添加一个项目时,计算机必须搜索空间以适合该项目。这就是为什么动态分配在未在内存池上或使用池分配器完成时会“减慢”速度的原因。如果您在进行多线程处理,那么对于繁重的 STL 应用程序,可以使用Hoard 分配器TBB Intel版本。

Now, when memory is fragmented two things can occur:

现在,当内存碎片化时,可能会发生两件事:

  1. There will have to be more searches to find a good space to stick "large" objects. That is, with many small objects scattered about finding a nice contigous chunk of memory could under certain conditions be difficult (these are extreme.)
  2. Memory is not some easily read entity. Processors are limited to how much they can hold and where. They do this by swapping pages if an item they need is one place but the current addresses are another. If you are constantly having to swap pages, processing can slow down (again, extreme scenarios where this impacts performance.) See this posting on virtual memory.
  1. 必须进行更多的搜索才能找到一个合适的空间来放置“大”物体。也就是说,在某些情况下,许多小对象分散在寻找一块好的连续内存块上可能很困难(这些都是极端的。)
  2. 内存不是一些容易阅读的实体。处理器受限于它们可以容纳的数量和位置。如果他们需要的项目在一个地方但当前地址在另一个地方,他们通过交换页面来实现这一点。如果您经常需要交换页面,则处理速度可能会变慢(同样,这会影响性能的极端情况。)请参阅有关虚拟内存的帖子。