c++_memory_arena_implications_blog

C++ Speicherregionen und ihre Auswirkungen

robert seilbeck
von Robert Seilbeck
Dezember 11, 2019
Lesezeit: 5 Minuten

Speicheregionen wurden in der voreingestellten C++ Speicherzuordnung unter Linux eingefรผhrt, um die Leistungsfรคhigkeit speicherintensiver Multithread-Anwendungen zu verbessern. Zuvor musste jede Speicherzuordnung synchronisiert werden. Dies fรผhrte dazu, dass die Speicherzuordnung hรคufig Leistungsengpรคsse verursachte.

Speicherregionen lรถsen dieses Problem durch die Einrichtung mehrerer Speicher-Pools. Diese unterstรผtzen die Speicherzuordnung mit mehreren simultanen Threads (mehr รผber Speicherregionen erfahren Sie in diesem hervorragenden Blogbeitrag: https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/).

In dem Blogbeitrag geht es um die Frage, wie sich dies auf das beobachtete Speicherverhalten auswirkt. Diese Frage ist deshalb relevant, weil es fรคlschlicherweise leicht als Speicherleak interpretiert werden kann.

So werden Speicherregionen fรคlschlicherweise als Speicherleaks interpretiert

Das Programm startet mehrere separate Workerthreads. Dabei gibt es zwei verschiedene Arten von Threads: 30MB-Workerthreads und 100MB-Workerthreads. Der 30MB-Workerthread weist 30 MB Daten zu und initialisiert sie.

Die Daten werden nach 100 Millisekunden freigegeben. Das passiert zehnmal nacheinander. Der 100MB-Workerthread tut genau dasselbe, allerdings mit 100MB-Blรถcken. Welche Art von Workerthread und wie viele davon ausgelรถst werden, lรคsst sich รผber Befehlszeilenparameter einstellen.

Sobald alle Workerthreads ihre Arbeit getan haben, wartet das Programm auf weitere Benutzerbefehle. Der Benutzer hat drei Mรถglichkeiten: Die erste beendet das Programm, die zweite fรผhrt malloc_trim(0) aus und die dritte druckt รผber malloc_stats() Statistiken zur Speicherregion aus.

Die folgenden Versuche wurden unter Ubuntu 16.04 mit einer 8-Kern CPU (4 physische) durchgefรผhrt.

Die Tabelle unten veranschaulicht den residenten Prozessspeicher fรผr unterschiedliche Worker-Typen und -Anzahlen, nachdem alle Worker ihre Arbeit erledigt und sรคmtliche Daten freigegeben haben.

ubuntu worker types and worker number combinations

Die 900 MB residenter Speicher nach dem vierten Durchlauf lohnen einen genaueren Blick. Die naheliegende Vermutung wรคre ein Speicherleck, das sich aber mithilfe von Tools wie Valgrind ausschlieรŸen lรคsst. Die eigentliche Ursache finden wir, wenn wir einen Blick auf die Statistiken zu den Speicherregionen werfen, die wir รผber malloc_stats() erhalten. Beim ersten Durchlauf erzeugt malloc_stats() beispielsweise die folgende Ausgabe:

c plus arena statistics using malloc stats

Eine Erlรคuterung dieses Konzepts finden Sie in diesem Artikel, der auf einem โ€žLightning Talkโ€œ basiert, welcher anlรคsslich einer Konferenz der C++ Anwendergruppe in Mรผnchen gehalten wurde und beschreibt, wie Speicherregionen zu vermeintlichen Speicherlecks fรผhren kรถnnen. In beiden Fรคllen wird das folgende Programm verwendet: https://github.com/celonis-se/memory-arena-example/blob/master/main.cpp

Testergebnisse nach Speicherregion

Die Ausgabedaten zeigen, wie viele Speicherregionen vorhanden sind, wie groรŸ diese sind und wie viel Speicher tatsรคchlich genutzt wird. Die Ergebnisse der einzelnen Testlรคufe finden sich in der folgenden Tabelle:

c plus arena test results

Die Tests deuten darauf hin, dass fรผr jeden Workerthread eine eigenstรคndige Speicherregion erstellt wird. AuรŸerdem scheint es so, als machten die Speicherregionen keinen Speicherplatz fรผr das Betriebssystem verfรผgbar, obwohl dieses vollkommen leer ist.

Die Unterschiede in der GrรถรŸe der Speicherregionen zwischen den 100MB-Workerthreads und den 30MB-Workerthreads lรคsst sich dadurch erklรคren, dass groรŸe zugewiesene Speicherblรถcke anders als kleine behandelt werden. Denn wรคhrend kleinere Speicherblรถcke einer bestimmten Speicherregion zugeordnet werden, erfolgt die Zuordnung grรถรŸerer Blรถcke per mmap, um eine รผbermรครŸige Fragmentierung zu vermeiden. Weitere Informationen zu diesem Thema finden Sie hier: https://www.linuxjournal.com/article/6390

Im Hinblick auf das Problem der fehlenden Rรผckgabe des Speicherplatzes an das Betriebssystem empfiehlt sich die Lektรผre eines Posts auf stackoverflow zum Thema Speichermanagement in Multi-Thread-Umgebungen mit malloc_trim.

Verwendung von Malloc_Trim

Die folgende Tabelle zeigt die Statistiken zu den Speicherregionen nach der Durchfรผhrung von malloc_trim. Laut Dokumentation versucht dieses, von oben freien Speicherplatz aus dem Heap freizugeben:

arena states applying malloc trim

Die Tests zeigen, dass nur 30 MB โ€“ die GrรถรŸe einer Speicherregion โ€“ freigegeben werden. Weitere Untersuchungen zeigen, dass malloc_trim ausschlieรŸlich die ungenutzten Bytes aus dem Hauptspeicher an das Betriebssystem zurรผckgibt.

Nach unserem Kenntnisstand existiert derzeit keine Mรถglichkeit, den Speicherplatz fรผr das Betriebssystem nutzbar zu machen, was wiederum einen betrรคchtlichen Speicher-Overhead verursachen kann.

Um diesen zu begrenzen, ist die Anzahl der Speicherregionen standardmรครŸig auf das Achtfache der Anzahl an Cores begrenzt (einschl. Hyperthreads). Da das hier verwendete Gerรคt acht Kerne besitzt, sind somit 64 Speicherregionen mรถglich.

8 core machine 64 arenas results

Wenn mehr als 64 Workerthreads aktiv sind, werden keine weiteren Speicherregionen erstellt. Stattdessen kรถnnen die vorhandenen aber wachsen.

Speicherregionen in C++ โ€“ Fazit

Speicherregionen kรถnnen die Leistungsfรคhigkeit deutlich verbessern, aber auch einen betrรคchtlichen Speicher-Overhead verursachen. Das gilt insbesondere fรผr Multi-Threaded-Programme mit langer Laufzeit.

Dieses Verhalten kann leicht als Speicherleck missverstanden werden. Bestehen Zweifel, ob tatsรคchlich ein Speicherleck vorliegt oder der Speicher in Speicherregionen aufgeteilt worden ist, kann dies รผber malloc_stats() mithilfe der Statistiken รผberprรผft werden.

robert seilbeck
Robert Seilbeck
Head of Back-end Development, Celonis

Abonnieren Sie unseren monatlichen Newsletter

We've received your submission
Please fill in all the fields

Indem Sie dieses Formular absenden, stimmen Sie der Speicherung und Verarbeitung Ihrer personenbezogenen Daten durch Celonis gemรครŸ unserer Datenschutzrichtlinie zu.
Lieber Besucher, wir haben festgestellt, dass Sie eine veraltete Browser-Version verwenden. Teile dieser Seite werden von Ihrem Browser nicht korrekt dargestellt. Fรผr eine korrekte Funktionsweise der Seite empfehlen wir Ihnen, einen alternativen Browser zu verwenden oder Ihren Browser auf eine unterstรผtzte Version anzuheben.