Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Memory fragmentation requires foreknowledge about memory allocation, so I'll need to set some concepts first.</p> <p><strong>Memory Allocation</strong></p> <p>When you call operator <code>new</code> (which by default will often call <code>malloc</code> behind the scenes), you do not directly request memory from the OS, instead what happens (generally) is that:</p> <ul> <li>you call <code>malloc</code> for 76 bytes, it looks if such is available: <ul> <li>if it is not, it request a page (usually 4KB) from the OS, and <em>prepare</em> it</li> </ul></li> <li>it then serves you the 76 bytes you asked for</li> </ul> <p>Memory fragmentation may happen at two levels:</p> <ul> <li>You may exhaust your virtual address space (not so easy with 64bits platforms)</li> <li>You may have nearly empty pages that cannot be reclaimed and yet cannot serve the requests you make</li> </ul> <p>Generally, since <code>malloc</code> should call pages 4KB at a time (unless you ask for a bigger chunk in which case it will choose a bigger multiple of 4KB), you should never exhaust your address space. It happened on 32bits machine (limited to 4GB) for unusually large allocations though.</p> <p>On the other hand, if your implementation of <code>malloc</code> is too naive, you may end up with fragmented memory blocks and thus have a much higher memory footprint than what you really use. This is usually what the term <em>memory fragmentation</em> refers to nowadays.</p> <p><strong>Typical Strategy</strong></p> <p>When I say <em>naive</em> I refer to, for example, your idea of allocating everything continuously. This is a bad idea. This is typically <em>not</em> what happens.</p> <p>Instead, the good <code>malloc</code> implementations today use pools.</p> <p>Typically, they will have pools <em>per size</em>:</p> <ul> <li>1 byte</li> <li>2 bytes</li> <li>4 bytes</li> <li>...</li> <li>512 bytes</li> <li>...</li> <li>4KB and more are handled specially (directly)</li> </ul> <p>And when you make a request, they will find the pool with the minimum size that can satisfy it, and this pool will serve you.</p> <p>Because in a pool all requests are served with the same size, there is no fragmentation within the pool as a <em>free</em> cell can be used for any incoming request.</p> <p><strong>So, fragmentation ?</strong></p> <p>Nowadays, you should not observe fragmentation per se.</p> <p>However you can still observe memory holes. Suppose that a pool is handling objects of 9 to 16 bytes and you allocate say 4,000,000 of them. This requires at least 16,000 pages of 4KB. Now suppose that you deallocate all but 16,000 of them, but deviously so that one object still lives for each page. The pages cannot be reclaimed by the OS, as you still use them, however since you only use 16 bytes out of 4KB, the space is quite wasted (for now).</p> <p>Some languages with Garbage Collection may handle those cases with <em>compaction</em>, however in C++, relocating an object in memory cannot be done because user has direct control over object addresses. </p> <p><strong>Magic container</strong></p> <p>I do not know of any such beast. I do not see why it would be useful either.</p> <p><strong>TL;DR</strong></p> <p>Don't worry about fragmentation.</p> <p><em>Note: "experts" may want to write their own pool allocation mechanism, I would like to remind them not to forget about alignment</em></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload