Hallo C-Cracks, Ich habe folgendes Problem. Ich habe eine Bibliothek, die mit malloc() sehr viele sehr kleine Speicherbereiche alloziiert. In meiner Software nutze ich auch malloc(). Nun benötige ich die Daten der Bibliothek nur temporär und nach einem free() habe ich dann viele kleine Speicherbereiche, die nicht an das Betriebssystem zurückgegeben werden können. Ich suche nun eine Implementierung von malloc() und free(), die ich in dieser Bibliothek verwenden möchte. Ich bin bei meinen Recherchen auf MMalloc (GNU memory-mapped malloc) gestoßen, welches für mich ideal erscheint. Leider habe ich diese Software nirgends gefunden. Weiß jemand, was damit passiert ist? Kennt jemand Alternativen? mfg, Stefan.
Alternative wäre, zu Beginn einen ausreichend großen Speicherbereich mit Standard-malloc() anzufordern und dann innerhalb dieses Bereiches mit einem eigenen malloc() (kann prinzipiell auf dem Quelltext des Standard-malloc()s basieren) Speicherstücke zuzuweisen. Hat den Vorteil, dass das Betriebssystem nur einen einzigen Riesenblock verwaltet, der dann logischerweise nix mehr fragmentiert.
Stefan May wrote: > Nun benötige ich die Daten der Bibliothek nur > temporär und nach einem free() habe ich dann viele kleine > Speicherbereiche, die nicht an das Betriebssystem zurückgegeben werden > können. Woraus schlussfolgerst du dies, und auf welchem System arbeitest du überhaupt? Jedes vernünftige malloc() sollte Blöcke wieder zusammenfassen können, um später neu daraus zu allozieren. Eine Rückgabe an das Betriebssystem war lange Zeit nicht implementiert, später wurde sie es in der Regel, aber dafür ist sie bei heutigen VM-basierten Systemen oft genug kaum wirklich sinnvoll. Im Zweifelsfalle wird dadurch lediglich die Belastung des swap reduziert.
Hallo Jörg, Sorry, das war natürlich wichtig. Betriebssystem ist Linux Kernel 2.6.18, libc6 2.3.6. Meine Schlußfolgerung ziehe ich aus der Größe des Prozesses in top und aus Durchläufen mit dem Memory-Profiler massif in Valgrind. Eine Grafik habe ich mal angehängt. Trotz der Freigabe des Speicher durch free, zu sehen in der Grafik, ändert sich die Größe in top nicht. Auf dem System habe ich leider keinen Swap. Den kann ich auch nicht hinzufügen, weil die Maschine nur eine CF-Karte als Massenspeicher besitzt. Mehr RAM ist leider keine Option, da es sich um so einen blöden Industriecomputer ohne Aufrüstmöglichkeiten handelt. Das Zusammenfassen von großen Blöcken durch malloc() nützt mir leider gar nichts, da ich es in meiner Software gar nicht brauche. Ich benötige den Speicher nur kurzfristig während der Start-Phase. mfg, Stefan.
Stefan May wrote: > Trotz der Freigabe des > Speicher durch free, zu sehen in der Grafik, ändert sich die Größe in > top nicht. Was ja letztlich eine virtuelle Größe ist, klar. VM-Systeme funktionieren so richtig nur mit Swap. Du kannst dir mal das "phkmalloc" vom FreeBSD angucken. Meines Wissens gibt das in der Tat VM ans System zurück. Ich habe es mit paar Tweaks schon erfolgreich unter Linux compiliert, um damit eine memory corruption in einem Python-Modul (der auch nur mittels Swig automatisch generiert war) zu debuggen. phkmalloc besitzt dafür ein paar nützliche Fietschers wie die Möglichkeit, allen allozierten Speicher mit einem Bitmuster zuzumüllen (sodass nicht ,aus Versehen' hinterher alles 0 ist und dann der Test auf einen Nullzeiger ungewollt einen nicht initialisierten Zeiger überspringen kann) und einen abort() beim Auftreten der ersten Unstimmigkeit zu erzwingen. Natürlich alles optional, wobei man die Optionen auf drei verschiedenen Wege spezifi- zieren kann.
Speicher an das System zurückgeben... Na ja, das funktioniert unter Unix nicht so richtig (ist aber normalerweise auch nicht notwendig...). Grund ist, daß unter Unix (und ähnlichen Systemen) bei einer Speicheranforderung an das Betriebssystem (mittels brk) lediglich die Speichergrenze in den Heap für den Prozess verschoben wird (wir haben ja virtuelle Speicherverwaltung). Um nun Speicher an das System zurückzugeben, muß diese Grenze wieder erniedrigt werden. Das geht aber nur, wenn der Prozess nicht inzwischen dahinter Speicher alloziert hat (im groben heißt das, daß der zuletzt allozierte Speicher auch zuerst freigegebn wird - falls er nicht in Lücken gefüllt werden konnte). Manche Unixe, z.B. auch HP-UX haben das implementiert, allerdings hat das nur mit speziell dafür gestrickter Software (manchmal) Erfolg.... Einfacher ist es, den Swap zu erhöhen, dann landet der freigegebene, aber nicht mehr gebrauchte Speicher dort und kostet nur Plattenplatz... Wenn man wirklich große Stücke Speicher braucht und wieder freigeben will, dann geht man so vor wie im Originalposting beschrieben - Speicher als memory map holen und freigeben. Ich wusste bisher gar nicht, das es das als library gibt, ich hätte das Rad neu erfunden... Link für mmalloc erggogelt z.B. http://www.geocities.com/SiliconValley/Circuit/5426/mmalloc.html
Hallo Berhard, Das von Dir gefundene mmalloc ist leider nicht das, was ich meinte. Ich habe per Google nur ein PDF gefunden: http://www.gnuarm.com/pdf/mmalloc.pdf Trotzdem ist Dein mmalloc interessant, wenn auch der Code ziemlich alt aussieht (Mitte 1998, also voriges Jahrtausend :-) mfg, Stefan.
Stefan May wrote: > Trotzdem ist Dein mmalloc interessant, wenn auch der Code ziemlich alt > aussieht (Mitte 1998, also voriges Jahrtausend :-) Ja, aber die Funktionalität in Unix ist ja viel älter, und erprobt. D.h. auch zehn Jahre alter Code ist heute noch gültig...
noch eins... es scheint, als wäre ein mmalloc auch im gdb implementiert und benutzt, vielleicht mal gdb source code durchsehen...
Bernhard M. wrote: > Das geht aber > nur, wenn der Prozess nicht inzwischen dahinter Speicher alloziert hat > (im groben heißt das, daß der zuletzt allozierte Speicher auch zuerst > freigegebn wird - falls er nicht in Lücken gefüllt werden konnte). Wenn er aber, wie er schreibt, nach der Initialisierung allen Speicher wieder freigegeben hat, sollte das funktionieren. phkmalloc jedenfalls kann das. Hier ein kleines FreeBSD-Beispiel:
1 | #include <sys/types.h> |
2 | #include <stdio.h> |
3 | #include <unistd.h> |
4 | |
5 | void *p1, *p2; |
6 | |
7 | int
|
8 | main(void) |
9 | {
|
10 | printf("Initial break value: %p\n", sbrk(0)); |
11 | p1 = malloc(100000); |
12 | printf("2nd break value: %p\n", sbrk(0)); |
13 | p2 = malloc(200000); |
14 | printf("3rd break value: %p\n", sbrk(0)); |
15 | free(p1); |
16 | printf("4th break value: %p\n", sbrk(0)); |
17 | free(p2); |
18 | printf("5th break value: %p\n", sbrk(0)); |
19 | |
20 | return 0; |
21 | }
|
Ausgabe:
1 | Initial break value: 0x8049918 |
2 | 2nd break value: 0x8065000 |
3 | 3rd break value: 0x8096000 |
4 | 4th break value: 0x8096000 |
5 | 5th break value: 0x805c000 |
Dass der letzte Wert hier nicht gleich dem ersten ist dürfte daran liegen, dass zwischenzeitlich stdio-Puffer hinzu gekommen sind, die nicht freigegeben werden können. Aber das sollte dem OP ja nicht passieren. Es ist deutlich erkennbar, dass Speicher ans System zurück gegeben worden ist. Auch phkmalloc ist übrigens von 1994... Aber OK, ich sehe im CVS-Log, dass es seither doch noch einige Veränderungen erfahren hat.
MM-alloc ist doch schon in der GNU-libc eingebaut oder täusch ich mich da jetzt?!
@haku: Ja, Du täuscht Dich. Die GNU-libc nutzt zwar mmap. Nach dem oben geposteten PDF kann man aber Speicher-Pools angeben. Ich bin das Problem jetzt anders angegangen. Ich habe meinen vorhandenen Code neu geschrieben, so daß er nicht mehr viele kleine Blöcke mit malloc holt. Meine Datenstruktur hat jetzt eine konstante Größe und ich reserviere mir immer gleich eine recht große Zahl. Diese verwalte ich dann allein. Der Vorteil: ich muß keinen eigenen, vielleicht kaputten Memory-Allocator verwenden. Und zwei ich nutze das GNU-libc malloc aus, welches bei großen Chunks mit mmap arbeitet. @Jörg: phkmalloc habe ich ausprobiert und es hat relativ gut funktioniert. Bis auf die mir unerklärlichen Segmentation-faults.... ;-) Ich habe dann die beschriebene Lösung favorisiert. Leider reichen meine C/Unix-Kenntnisse an der Stelle nicht aus. Vielen Dank für Eure Mithilfe. Ich habe eine Menge über Speichermanagement gelernt. Mann, ich bin froh, daß ich mich in Java darum nicht kümmern muß. :-) mfg, Stefan.
Stefan May wrote: > @Jörg: phkmalloc habe ich ausprobiert und es hat relativ gut > funktioniert. Bis auf die mir unerklärlichen Segmentation-faults.... ;-) Debug-Optionen anwerfen und die Probleme suchen... Zu 99,9 % liegen sie in deinem Code... Wie gesagt, ich hab's auch unter Linux als memory allocator für ein Python schon benutzt, und nachdem ich damit den off-by-one-error in besagtem Swig-Modul gefunden habe (den ich mit dem originalen GNU-malloc nie wirklich einkreisen konnte), war es völlig stabil.
Hallo Jörg, Ich habe keinen anderen Memory-Allocator verwendet, weil das nur die Symptome bekämpfen würde. Der Code ist sehr ungeschickt, da tut eine Refaktorisierung ganz gut. Den Fehler bei der Verwendung von phkmalloc habe ich auch schon gefunden. Deine Vermutung war natürlich richtig, wie zu erwarten lag das Problem in meinem Code. Wenn das Forum erlaubt, mißbrauche ich Euch mal als seelischen Mülleimer: AAAAHHH, WIE KANN MAN NUR SO MIESEN CODE SCHREIBEN!!!!!1!!1ELF!! mfg, Stefan.
Stefan May wrote: > Wenn das Forum erlaubt, mißbrauche ich Euch mal als seelischen > Mülleimer: AAAAHHH, WIE KANN MAN NUR SO MIESEN CODE > SCHREIBEN!!!!!1!!1ELF!! Nun, wenn du dich jetzt wohler fühlst, sei dir das gestattet. :-)) Freut mich, dass du's gefunden hast und jetzt hoffentlich mit dem Resultat zufrieden bist.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.