Forum: PC-Programmierung Speicherfragmentierung


von Stefan M. (Gast)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Stefan M. (Gast)


Lesenswert?

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.

von Stefan M. (Gast)


Angehängte Dateien:

Lesenswert?

Grafik natürlich vergessen. :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Bernhard M. (boregard)


Lesenswert?

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

von Stefan M. (Gast)


Lesenswert?

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.

von Bernhard M. (boregard)


Lesenswert?

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...

von Bernhard M. (boregard)


Lesenswert?

noch eins... es scheint, als wäre ein mmalloc auch im gdb implementiert 
und benutzt, vielleicht mal gdb source code durchsehen...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

MM-alloc ist doch schon in der GNU-libc eingebaut oder täusch ich mich 
da jetzt?!

von Stefan M. (Gast)


Lesenswert?

@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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Stefan M. (Gast)


Lesenswert?

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.

von Bobby (Gast)


Lesenswert?

Mal überlegt, ganz ohne malloc() auszukommen ?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Stefan M. (Gast)


Lesenswert?

@Bobby: Hab ich gemacht, den Code umgeschrieben, keine Probleme mehr.

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
Noch kein Account? Hier anmelden.