2013-03-20 15 views
5

Die manual page hat mir so viel erzählt und durch sie weiß ich viel Hintergrundwissen über die Speicherverwaltung von "glibc".Was bedeutet "malloc_trim (0)" wirklich?

Aber ich bin immer noch verwirrt. tut "malloc_trim (0)" (beachten Sie, Null als Parameter) bedeuten (1.) wird der gesamte Speicher im Abschnitt "Heap" an OS zurückgegeben? Oder (2.) nur alle "ungenutzten" Speicher der obersten Region des Heap wird an OS zurückgegeben werden?

Wenn die Antwort ist (1.), was ist, wenn der noch verwendete Speicher im Heap? Wenn der Heap irgendwo Orte verwendet hat, werden sie eliminiert oder die Funktion wird nicht erfolgreich ausgeführt?

Während, wenn die Antwort (2.), was ist mit den „Löchern“ an Orten statt oben auf der Halde? Sie mehr ungenutzte Speicher sind, aber die oberste Region des Haufens noch Wird dieser Anruf effizient funktionieren?

Danke.

Antwort

4

Die Manpage für malloc_trim besagt, dass es freien Speicher freigibt. Wenn also Speicher im Heap zugewiesen wird, wird der gesamte Heap nicht freigegeben. Der Parameter ist vorhanden, wenn Sie wissen, dass Sie immer noch eine bestimmte Menge an Speicher benötigen. Wenn Sie also mehr freigeben, wird glibc später unnötige Arbeit verrichten müssen.

Bei Löchern ist dies ein Standardproblem bei der Speicherverwaltung und beim Zurückgeben von Speicher an das Betriebssystem. Die primäre Low-Level-Heapverwaltung, die dem Programm zur Verfügung steht, ist brk und sbrk, und alles, was sie tun können, ist das Erweitern oder Verkleinern des Heap-Bereichs durch Ändern des oberen Bereichs. Also gibt es keine Möglichkeit für sie, Löcher in das Betriebssystem zu bringen. Sobald das Programm sbrk aufgerufen hat, um mehr Heapspeicher zuzuweisen, kann dieser Speicherplatz nur zurückgegeben werden, wenn der Anfang dieses Speicherplatzes frei ist und zurückgegeben werden kann.

Beachten Sie, dass es andere, komplexere Möglichkeiten gibt, Speicher zuzuordnen (z. B. mit anonymem Code mmap), die möglicherweise andere Einschränkungen haben als die sbrk -basierte Zuordnung.

+0

Es gibt jetzt Methode zum Zurückbringen von Löchern in der Mitte des Heap zurück zum Betriebssystem: MADV_DONTNEED (und manchmal MADV_FREE): http://code.metager.de/source/xref/gnu/glibc/malloc/malloc.C# 4535 'mtrim (mstate av, size_t-Pad) ... __madvise (paligned_mem, Größe & ~ psm1, MADV_DONTNEED);'. 'madvise' mit solchen Flags markiert Seiten, die für die Anwendung nicht benötigt werden, das Betriebssystem kann Daten von ihnen zerstören und den physischen Speicherplatz aufheben; Der nächste Zugriff auf die Seite kann den Seitenfehler erzeugen, um die virtuelle Seite in den physischen Raum umzuordnen. – osgx

+0

Code wurde hinzugefügt in https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=68631c8eb92ff38d9da1ae34f6aa048539b199cc 68631c8eb92ff38d9da1ae34f6aa048539b199cc "(mTRIm): Zusätzlich iterieren über alle freien Blöcke und Verwende madvise, um Speicher für all jene Blöcke freizugeben, die mindestens eine Speicherseite enthalten. " - \t Ulrich Drepper 16.12.2007 (glibc 2.9) – osgx

0

Man Seite von malloc_trim wurde hier begangen: https://github.com/mkerrisk/man-pages/blob/master/man3/malloc_trim.3 und wie ich sie verstehe, wurde es von Mann-Seiten Projekt Betreuers, Kerrisk im Jahr 2012 von Grund auf neu geschrieben: https://github.com/mkerrisk/man-pages/commit/a15b0e60b297e29c825b7417582a33e6ca26bf65

Wie kann ich grep the glibc's git, there are no man pages in the glibc, und nicht zu malloc_trim manpage begehen um diesen Patch zu dokumentieren. Die beste und die einzige Dokumentation von glibc malloc ist sein Quellcode: https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c Es gibt malloc_trim Kommentare von malloc/malloc.c:

Additional functions: 
malloc_trim(size_t pad); 
609 /* 
610 malloc_trim(size_t pad); 
611 
612 If possible, gives memory back to the system (via negative 
613 arguments to sbrk) if there is unused memory at the `high' end of 
614 the malloc pool. You can call this after freeing large blocks of 
615 memory to potentially reduce the system-level memory requirements 
616 of a program. However, it cannot guarantee to reduce memory. Under 
617 some allocation patterns, some large free blocks of memory will be 
618 locked between two used chunks, so they cannot be given back to 
619 the system. 
620 
621 The `pad' argument to malloc_trim represents the amount of free 
622 trailing space to leave untrimmed. If this argument is zero, 
623 only the minimum amount of memory to maintain internal data 
624 structures will be left (one page or less). Non-zero arguments 
625 can be supplied to maintain enough trailing space to service 
626 future expected allocations without having to re-obtain memory 
627 from the system. 
628 
629 Malloc_trim returns 1 if it actually released any memory, else 0. 
630 On systems that do not support "negative sbrks", it will always 
631 return 0. 
632 */ 
633 int  __malloc_trim(size_t); 
634 

Befreit von der Mitte des Blockes nicht als Text in malloc dokumentiert/malloc.c und nicht im man-pages-Projekt dokumentiert. Man-Seite von 2012 kann die erste Manpage der Funktion sein, die nicht von den Autoren von glibc geschrieben wurde. Die Infoseite von glibc erwähnt nur M_TRIM_THRESHOLD von 128 KB: https://www.gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html#Malloc-Tunable-Parameters und listet die malloc_trim Funktion https://www.gnu.org/software/libc/manual/html_node/Summary-of-Malloc.html#Summary-of-Malloc nicht auf (und dokumentiert auch nicht memusage/memusagestat/libmemuseage.so).

Im Dezember 2007 gab es commit https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=68631c8eb92ff38d9da1ae34f6aa048539b199cc von Ulrich Drepper (es ist Teil von glibc 2.9 und höher), die mtrim Implementierung geändert (aber keine Dokumentation oder man-Seite nicht, da es keine man-Seiten in glibc) sind ändern:

  • malloc/malloc.c (public_mTRIm): iterieren alle Arenen und Anruf

mTRIm für alle von ihnen. (mTRIm): Zusätzlich über alle freien Blöcke iterieren und madvise verwenden, um Speicher für all jene Blöcke freizugeben, die mindestens eine Speicherseite enthalten.

Ungenutzte Teile Brocken (überall, einschließlich Stücke in der Mitte), ausgerichtet auf die Seitengröße und mit einer Größe mehr als Seite als MADV_DONTNEED markiert werden können https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=c54c203cbf1f024e72493546221305b4fd5729b7;hp=1e716089a2b976d120c304ad75dd95c63737ad75;hb=68631c8eb92ff38d9da1ae34f6aa048539b199cc;hpb=52386be756e113f20502f181d780aecc38cbb66a

 INTERNAL_SIZE_T size = chunksize (p); 

     if (size > psm1 + sizeof (struct malloc_chunk)) 
     { 
      /* See whether the chunk contains at least one unused page. */ 
      char *paligned_mem = (char *) (((uintptr_t) p 
              + sizeof (struct malloc_chunk) 
              + psm1) & ~psm1); 

      assert ((char *) chunk2mem (p) + 4 * SIZE_SZ <= paligned_mem); 
      assert ((char *) p + size > paligned_mem); 

      /* This is the size we could potentially free. */ 
      size -= paligned_mem - (char *) p; 

      if (size > psm1) 
       madvise (paligned_mem, size & ~psm1, MADV_DONTNEED); 
     } 

Dies ist eine von insgesamt zwei Verwendungen nun von madvise mit MADV_DONTNEED in glibc, ein für Oberteil von Halden (shrink_heap) und anderer Kennzeichnung jeden Chunk (mtrim): http://code.metager.de/source/search?q=MADV_DONTNEED&path=%2Fgnu%2Fglibc%2Fmalloc%2F&project=gnu

H A D arena.c 643 __madvise ((char *) h + new_size, diff, MADV_DONTNEED); 
H A D malloc.c 4535 __madvise (paligned_mem, size & ~psm1, MADV_DONTNEED); 

Wir können die malloc_trim mit diesem einfachen C-Programm testen (test_malloc_trim.c) und strace/ltrace:

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

int main() 
{ 
    int *m1,*m2,*m3,*m4; 
    printf("%s\n","Test started"); 
    m1=(int*)malloc(20000); 
    m2=(int*)malloc(40000); 
    m3=(int*)malloc(80000); 
    m4=(int*)malloc(10000); 
    // check that all arrays are allocated on the heap and not with mmap 
    printf("1:%p 2:%p 3:%p 4:%p\n", m1, m2, m3, m4); 
    // free 40000 bytes in the middle 
    free(m2); 
    // call trim (same result with 2000 or 2000000 argument) 
    malloc_trim(0); 
    // call some syscall to find this point in the strace output 
    sleep(1); 
    free(m1); 
    free(m3); 
    free(m4); 
    // malloc_stats(); malloc_info(0, stdout); 
    return 0; 
} 

gcc test_malloc_trim.c -o test_malloc_trim, strace ./test_malloc_trim

write(1, "Test started\n", 13Test started 
)   = 13 
brk(0)         = 0xcca000 
brk(0xcef000)       = 0xcef000 
write(1, "1:0xcca010 2:0xccee40 3:0xcd8a90"..., 441:0xcca010 2:0xccee40 3:0xcd8a90 4:0xcec320 
) = 44 
madvise(0xccf000, 36864, MADV_DONTNEED) = 0 
... 
nanosleep({1, 0}, 0x7ffffafbfff0)  = 0 
brk(0xceb000)       = 0xceb000 

So gab es madvise mit MADV_DONTNEED für 9 Seiten nach malloc_trim(0) Rufen Sie an, wenn in der Mitte des Heaps ein Loch von 40008 Bytes war.

+0

Typische offizielle Position des GNU-artigen Projektbetreuers auf man-Seiten und andere Dokumentation: https://sourceware.org/bugzilla/show_bug.cgi?id=2531#c4 "Ulrich Drepper 2006-05-01 Die man-Seiten werden nicht in glibc gepflegt. Erzähle dies dem man page maintainer. " – osgx