PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [c] speicher freigeben



msi
12-08-2008, 18:06
hallo,

wenn ich mit malloc speicher alloziiert habe kann ich diesen ja mit free
freigeben. mein problem ist jedoch, dass dieser freie speicher noch
nicht wirklich an den kernel "zurückgegeben" wird, sondern dass
das programm (oder isses der kernel?) sich diesen speicher
in einem malloc-pool zurückhält [1].
da meine anwendung (serverprozess der sehr lange läuft) jedoch
zum teil wirklich viel speicherplatz braucht (bis zu 1gb),
meiste zeit jedoch kaum was, möchte ich, dass das betriebssystem
diesen speicher nutzen kann.

wie kann ich also den speicher wirklich freigeben?
mir ist klar dass bei genügend größer swap größe der speicherbereich (da er nicht genutzt ist) im swap landet, aber das reicht mir nicht.

danke, Markus

[1] http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/c_016_009.htm

peschmae
13-08-2008, 11:10
Also das ist nicht das was ich auf meinem Linux-System in der Praxis beobachte. Das ist in der allgemeinen Formulierung in der es da in dem von dir zitierten Buch steht einfach nur falsch.

Du brauchst dir da keine Sorgen zu machen - kannst du ja auch ganz einfach ausprobieren indem du ein Progrämmchen schreibst das zwischendurch mal ein paar GB Ram belegt und dir vor/nach der Freigabe den verfügbaren Arbeitsspeicher anschaust.

Es gibt allerdings sicherlich malloc-Implementierungen, die das so handhaben. Aber auf Desktop- und Serversystemen macht so etwas keinen Sinn und wird deshalb auch nicht so gemacht. (siehe z.B. http://www.ibm.com/developerworks/linux/library/l-memory/] oder auch Wikipedia bzgl des glibc allocators: http://en.wikipedia.org/wiki/Malloc#The_glibc_allocator)

MfG Peschmä

msi
13-08-2008, 21:48
habs getestet und der speicher wird leider wirklich nicht freigegeben
(speicherplatz anzeige via ps), aber wiederverwendet.
genauso hab ichs beobachtet


edit in deinem link sthet ja auch:
"free: This takes a pointer to a segment of memory allocated by malloc, and returns it for later use by the program or the operating system (actually, some malloc implementations can only return memory back to the program, not to the operating system)."

gooze
14-08-2008, 08:39
mal ein
watch -n 1 cat /proc/meminfo gemacht?
Und dann verglichen das Prog im anderen Terminal mehrfach zu öffnen und zu schliessen bzw. geschaut ob der Speicher wirklich immer weniger wird?

Axel

Obwohl, hat mich ja auch interessiert und mal im Ritchie nachgelesen: Da steht:


The function free causes the space pointed to ptr to be deallocated. This freed space is usually put into a pool of available memory and can be allocated in a later call to one of the three alloc functions.

peschmae
14-08-2008, 09:57
habs getestet und der speicher wird leider wirklich nicht freigegeben
(speicherplatz anzeige via ps), aber wiederverwendet.
genauso hab ichs beobachtet

Ich hatte das via free beobachtet; aber auch bei ps wird bei mir der Speicher wieder zurückgegeben (ausser ich mache was falsch?)



#include <stdio.h>
#include <stdlib.h>

int main() {
int* a = (int*) malloc(1024*1024*1024);
int i = 0;
for (i = 0; i < 1024*1024*1024/sizeof(int); i++)
*(a+i) = i;

printf("malloced 1GB\n");
getchar();

free(a);
printf("freed 1 GB\n");
getchar();

return 0;
}


Nach dem malloc:


peschmae@sid:/tmp$ ps -aux | grep test
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
peschmae 4870 10.2 25.8 1052228 1049008 pts/3 S+ 10:53 0:03 ./test


und nach dem free:


peschmae 4870 8.4 0.0 3648 432 pts/3 S+ 10:53 0:03 ./test




edit in deinem link sthet ja auch:
"free: This takes a pointer to a segment of memory allocated by malloc, and returns it for later use by the program or the operating system (actually, some malloc implementations can only return memory back to the program, not to the operating system)."

Some malloc implementation steht da, aber in Wikipedia steht dass die von GLibc den Speicher zurückgeben kann.

MfG Peschmä

gooze
14-08-2008, 10:49
ich muss msi aber rechtgeben.
Der Speicher wird auf dem Heap wieder für malloc und Co wieder freigegeben, aber dem Kernel steht der Space dann nicht mehr zur Verfügung. Jedenfalls sagt der Ritchie das auch ein paar Absätze weiter.

Axel

peschmae
14-08-2008, 11:33
Naja, Ritchie ist ja wohl nicht die Referenz in Bezug auf die GNU Libc. Ausserdem sagt er "usually".

Die GLibc Doku sagt schwammig:


Occasionally, free can actually return memory to the operating system and make the process smaller. Usually, all it can do is allow a later call to malloc to reuse the space. In the meantime, the space remains in your program as part of a free-list used internally by malloc.

http://www.gnu.org/software/libc/manual/html_mono/libc.html#Freeing-after-Malloc

Etwas klarer wird die Geschichte wenn man da guckt: http://www.gnu.org/software/libc/manual/html_mono/libc.html#Malloc-Tunable-Parameters



M_TRIM_THRESHOLD
This is the minimum size (in bytes) of the top-most, releasable chunk that will cause sbrk to be called with a negative argument in order to return memory to the system.


sbrk ist das Dingens das Malloc benutzt um Speicher vom System zu kriegen/zurückzugeben.

So wie ich das verstehe muss der Adressbereich obenrum frei sein damit sbrk den Speicher zurückgeben kann, was natürlich nicht zwingend der Fall ist auch wenn du die meisten der mit malloc angeforderten Speicherbereiche wieder freigegeben hast.



M_MMAP_THRESHOLD
All chunks larger than this value are allocated outside the normal heap, using the mmap system call. This way it is guaranteed that the memory for these chunks can be returned to the system on free. Note that requests smaller than this threshold might still be allocated via mmap.


Für mein Testprogramm wurde der Speicher also sofort zurückgegeben weil 1 GB natürlich viel grösser ist als der Wert den M_MMAP_THRESHOLD hat. Was auch immer das sein mag...

MfG Peschmä

peschmae
14-08-2008, 12:27
Ich habe noch mal schnell ein kleines Testprogrämmchen geschrieben um zu überprüfen ob ich die Doku richtig verstanden habe.

Folgendes:


#include <stdio.h>
#include <stdlib.h>

int main() {
const int len = 1024*1024;
void **a = (void**)malloc(len*sizeof(void*));
int i;
for (i = 0; i < len; i++)
a[i] = (void*)malloc(1024);

void* blocker = malloc(100);

printf("malloced 1GB\n");
getchar();


for (i = 0; i < len; i++)
free(a[i]);
printf("freed 1 GB\n");
getchar();


free(blocker);
printf("freed blocker\n");
getchar();

return 0;
}


a ist ein Pointer-Array. In der For-Schleife werden für die 1024*1024 Pointer in a jeweils 1024 Byte alloziert. Insgesamt 1 GB. Die 1024 Bytes sind jeweils so klein dass mmap nicht benutzt wird.

Nach den mallocs ist der Speicher voll:


peschmae 6562 4.8 26.4 1076820 1073588 pts/5 S+ 13:20 0:00 ./test


In einem nächsten Schritt werden weitere 100 Bytes alloziert - die sind (offenbar) zuoberst auf dem Heap. Anschliessend werden die 1 GB Speicher die zu den Pointern in a gehören wieder freigegeben. Nachher ist der Speicher immer noch belegt:


peschmae 6562 4.6 26.4 1076820 1073592 pts/5 S+ 13:20 0:00 ./test


Was daran liegt dass die oberste Adresse auf dem Heap vom Speicher in blocker belegt ist - die 1 GB darunter sind zwar frei, können aber mit sbrk nicht ans OS zurückgegeben werden weil sbrk nur die Heap-Obergrenze dynamisch verschieben kann.

Das geht erst wenn auch der blocker-Speicher weg ist:


peschmae 6562 4.3 0.2 11976 8760 pts/5 S+ 13:19 0:01 ./test


Fazit in Bezug auf die Ausgangsfrage: Es scheint als müsstest du sicherstellen dass du wirklich allen Speicher wieder freigibst der oben auf dem Heap ist (d.h. spät alloziiert wurde - wobei der Zusammenhang zwischen spät alloziiert und oben auf dem Heap ja nicht zwingend ist), damit der Speicher wieder ans OS zurückgegeben werden kann.

Oder genug grosse Speicherblöcke benutzen, damit mmap benutzt wird. Oder die Limits ändern dass häufiger mmap benutzt wird (wobei sich dann die Frage stellt ob das nicht plötzlich ineffizient wird - z.B. wegen Verwaltungsaufwand oder ob die Memory-Mapping-Tabellen irgendwo in ihrer Grösse beschränkt sind (läuft das eventuell in Hardware?); irgend einen Grund wird es schon haben dass die Methode normalerweise nur für grössere Speicherblöcke verwendet wird)

Interessanter Kommentar zum Thema: http://c-faq.com/malloc/free2os.es.html

MfG Peschmä

undefined
14-08-2008, 12:57
Wenn der Speicher vom Kernel nicht frei gegeben wird liegt es daran das die last deines Programms zu hoch ist.
Ein paar Infos zu dem Thema.
malloc ist Userspace und nicht Kernel, der Kernel kennt kein malloc sondern kmalloc und das ist nicht Userspace ;) Der Kernel verwaltet den Speicher unabhängig des laufenden Programms (Preemptives verhalten). Der Kernel sieht einfach nach wer wo wann und wie viel verbraucht in legt die reservierung fest. Wenn die last beständig hoch (viele veschiedene Prozesse auf eine Schnittstelle) ist wird ein SLAB/SLUB Layer angelegt und der ist erst mal save. Siehe ls /proc/slabinfo oder mein Programm kcmslabinfo (http://www.kde-apps.org/content/show.php/kcmslabinfo?content=62200)
Alleine dieses Thema verbraucht im Linux Kernel Handuch Buch 100 Seiten und ich habe es bis jetzt noch nicht ganz geschnallt. Außerdem kann man so wenig schreiben weil keiner weiss wie du deine Schnittstelle geschrieben hast.
Es gibt gerade für Netzwerk Schnittstellen im Kernel gesonderte bereiche.
Hier die Doku ist auch ganz gut http://www.oreilly.de/german/freebooks/linuxdrive2ger/get.html

panzi
15-08-2008, 13:00
Das was peschmae da getestet hat klingt interessant, den Java KANN mit so einer Situation umgehn. Java weiß wo "Pointer" auf einen Speicher liegen und somit kanns den Speicher verschieben und alle Pointer anpassen. Von dem her ist der Garbagecollector wesentlich Speichereffizienter. :)

msi
15-08-2008, 16:14
danke euch allen. Das Problem ist, wie peschmae im 2. Post geschrieben hat, dass eben nur speicher freigegeben wird, der "in der mitte" des heaps liegt.
werde mal schauen wie ich das anpasse.
danke!