2013-03-20 4129 views
5

manual page告诉我这么多,通过它我知道很多关于“glibc”的内存管理的背景知识。“malloc_trim(0)”的真正含义是什么?

但我仍然感到困惑。 “malloc_trim(0)”(注意零作为参数)意思是(1.)“堆”部分中的所有内存都将返回到OS?或者(2.)堆的最顶部区域中的所有“未使用”内存都将返回到操作系统?

如果答案是(1.),如果堆中仍然使用了内存,该怎么办?如果堆在某处使用了momery,它们是否会被淘汰,或者该功能无法成功执行?

而如果答案是(2.),何谈那些“”的地方,而不是在堆顶?他们不再是未使用的内存,但是堆的最上面的区域仍是使用,这种呼叫会有效地工作吗?

谢谢。

回答

4

malloc_trim的手册页说它释放空闲内存,所以如果在堆中分配了内存,它不会释放整个堆。如果你知道你仍然需要一定量的内存,那么这个参数就在那里,所以释放更多的内存会导致glibc以后不得不做不必要的工作。

至于漏洞,这是内存管理和将内存返回给操作系统的标准问题。该程序可用的主要低级堆管理是brksbrk,他们所能做的只是通过更改顶部来扩展或缩小堆区域。所以他们没有办法让操作系统返回漏洞;一旦程序调用sbrk来分配更多的堆,那么只有该空间的顶部是空闲的并且可以返回时才能返回该空间。

请注意,还有其他更复杂的方式来分配内存(例如匿名mmap),它可能与基于sbrk的分配有不同的约束。

malloc_trim
+0

现在有一种将堆中间的孔返回到操作系统的方法:MADV_DONTNEED(有时是MADV_FREE):http://code.metager.de/source/xref/gnu/glibc/malloc/malloc.c #4535'mtrim(mstate av,size_t pad)... __madvise(paligned_mem,size&〜psm1,MADV_DONTNEED);'。带有这种标志的“madvise”标志着应用程序不需要页面,OS可能会销毁它们的数据并取消映射物理空间;下一次访问页面可能会生成页面错误以将虚拟页面重新映射到物理空间。 – osgx 2017-02-16 11:48:45

+0

代码添加在https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=68631c8eb92ff38d9da1ae34f6aa048539b199cc 68631c8eb92ff38d9da1ae34f6aa048539b199cc“(mTRIm):此外迭代所有空闲块和使用madvise为所有包含至少一个内存页的块释放内存。“ - \t Ulrich Drepper 2007年12月16日(glibc 2.9) – osgx 2017-02-16 11:53:19

0

人页面在这里承诺:https://github.com/mkerrisk/man-pages/blob/master/man3/malloc_trim.3,并按照我的理解,它是由人的页面项目的维护者从头写起,kerrisk 2012年:https://github.com/mkerrisk/man-pages/commit/a15b0e60b297e29c825b7417582a33e6ca26bf65

,我可以grep the glibc's git, there are no man pages in the glibc,并没有承诺malloc_trim手册页记录这个补丁。的glibc的malloc最好的和唯一的文档是它的源代码:https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c 有来自malloc/malloc.cmalloc_trim评论:

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 

从块中间释放没有记录中的malloc文/ malloc.c并没有记录在man-pages项目中。 2012年的手册页可能是该函数的第一个手册页,不是由glibc的作者撰写的。 glibc的信息页只提​​到128 KB的M_TRIM_THRESHOLD: https://www.gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html#Malloc-Tunable-Parameters并且不列出malloc_trim函数https://www.gnu.org/software/libc/manual/html_node/Summary-of-Malloc.html#Summary-of-Malloc(并且它也不记录memusage/memusagestat/libmemusage.so)。

2007年12月,由Ulrich Drepper提交了https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=68631c8eb92ff38d9da1ae34f6aa048539b199cc(它是glibc 2的一部分)。9,并且改变mtrim实施新)(不过那是glibc无人页)它并没有改变任何文件或手册页:

  • 的malloc/malloc.c(public_mTRIm):遍历所有竞技场和电话

mTRIm所有这些。 (mTRIm):此外迭代所有空闲块并使用madvise为所有包含至少一个内存页面的块释放内存。

块的未使用的部分(任何地方,包括在中间块),页面大小对齐,并具有尺寸大于页可被标记为MADV_DONTNEEDhttps://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); 
     } 

这是总两种用法之一的madvise与glibc的MADV_DONTNEED现在,一个用于(shrink_heap)的堆顶部部分和其他被标记的任何块(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); 

我们可以用这个简单的C程序(test_malloc_trim.c)和strace/ltrace测试malloc_trim

#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_trimstrace ./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 

所以,有madviseMADV_DONTNEEDmalloc_trim(0)后9页调用时,在堆的中间有40008个字节的空洞。

+0

GNU-like项目维护人员在手册页和其他文档中的典型官方位置:https://sourceware.org/bugzilla/show_bug.cgi?id = 2531#c4“Ulrich Drepper 2006-05-01 man页面不是用glibc维护的,告诉man页面的维护者。“ – osgx 2017-02-16 13:06:55

相关问题