Die Speicherfragmentierung ist das gleiche Konzept wie die Festplattenfragmentierung: Sie bezieht sich auf die Verschwendung von Speicherplatz, da die verwendeten Bereiche nicht eng genug zusammengepackt sind.
Angenommen, Sie haben für ein einfaches Spielzeugbeispiel zehn Byte Speicher:
| | | | | | | | | | |
0 1 2 3 4 5 6 7 8 9
Ordnen wir nun drei Drei-Byte-Blöcke mit den Namen A, B und C zu:
| A | A | A | B | B | B | C | C | C | |
0 1 2 3 4 5 6 7 8 9
Geben Sie nun Block B frei:
| A | A | A | | | | C | C | C | |
0 1 2 3 4 5 6 7 8 9
Was passiert nun, wenn wir versuchen, einen Vier-Byte-Block D zuzuweisen? Nun, wir haben vier Bytes Speicher frei, aber wir haben nicht vier zusammenhängende Bytes Speicher frei, also können wir D nicht zuweisen! Dies ist eine ineffiziente Speichernutzung, da wir D hätten speichern können, dies aber nicht konnten. Und wir können C nicht verschieben, um Platz zu schaffen, da sehr wahrscheinlich einige Variablen in unserem Programm auf C zeigen und wir nicht alle diese Werte automatisch finden und ändern können.
Woher weißt du, dass es ein Problem ist? Das größte Zeichen ist, dass der virtuelle Speicher Ihres Programms erheblich größer ist als der tatsächlich verwendete Speicher. In einem Beispiel aus der Praxis hätten Sie viel mehr als zehn Bytes Speicher, sodass D erst ab Byte 9 zugewiesen würde und die Bytes 3-5 nicht verwendet würden, es sei denn, Sie hätten später etwas mit einer Länge von drei Bytes oder weniger zugewiesen.
In diesem Beispiel sind 3 Bytes nicht viel zu verschwenden. Betrachten Sie jedoch einen pathologischeren Fall, in dem zwei Zuordnungen von ein paar Bytes beispielsweise zehn Megabyte voneinander entfernt sind und Sie einen Block mit einer Größe von 10 Megabyte zuweisen müssen + 1 Byte. Sie müssen das Betriebssystem um mehr als zehn Megabyte mehr virtuellen Speicher bitten, um dies zu tun, obwohl Sie nur ein Byte davon entfernt sind, bereits genügend Speicherplatz zu haben.
Wie verhindern Sie das? Die schlimmsten Fälle treten in der Regel auf, wenn Sie häufig kleine Objekte erstellen und zerstören, da dies zu einem "Schweizer Käse" -Effekt mit vielen kleinen Objekten führt, die durch viele kleine Löcher getrennt sind, sodass keine größeren Objekte in diesen Löchern zugeordnet werden können. Wenn Sie wissen, dass Sie dies tun werden, besteht eine effektive Strategie darin, einen großen Speicherblock als Pool für Ihre kleinen Objekte vorab zuzuweisen und dann die Erstellung der kleinen Objekte in diesem Block manuell zu verwalten, anstatt sie zuzulassen Der Standard-Allokator behandelt dies.
Im Allgemeinen ist es weniger wahrscheinlich, dass der Speicher fragmentiert wird, je weniger Zuweisungen Sie vornehmen. STL geht damit jedoch ziemlich effektiv um. Wenn Sie eine Zeichenfolge haben, die die gesamte aktuelle Zuordnung verwendet und ein Zeichen an sie anfügt, wird sie nicht einfach ihrer aktuellen Länge plus eins neu zugewiesen, sondern ihre Länge verdoppelt . Dies ist eine Variation der Strategie "Pool für häufige kleine Allokationen". Die Zeichenfolge beansprucht einen großen Teil des Speichers, so dass sie mit wiederholten kleinen Vergrößerungen effizient umgehen kann, ohne wiederholte kleine Neuzuweisungen vorzunehmen. Tatsächlich machen alle STL-Container so etwas, sodass Sie sich im Allgemeinen nicht zu viele Gedanken über die Fragmentierung machen müssen, die durch die automatische Neuzuweisung von STL-Containern verursacht wird.
Obwohl natürlich STL Umhüllungen Pool nicht Speicher zwischen einander, so dass , wenn Sie viele kleine Behälter (eher als ein paar Container , die häufig der Größe verändert werden) erstellen Sie gehen zu Sorge haben , sich mit der Fragmentierung in der gleichen Art und Weise verhindern Sie würde für alle häufig erstellten kleinen Objekte, STL oder nicht.