Linux malloc_trim()能否从堆的中间释放内存?
我对glibc中实现的malloc_trim的行为感到困惑Linux malloc_trim()能否从堆的中间释放内存?,linux,memory,operating-system,malloc,glibc,Linux,Memory,Operating System,Malloc,Glibc,我对glibc中实现的malloc_trim的行为感到困惑 man malloc_trim [...] malloc_trim - release free memory from the top of the heap [...] This function cannot release free memory located at places other than the top of the heap. 当我现在查找malloc\u trim()(在malloc/malloc.c中)的
man malloc_trim
[...]
malloc_trim - release free memory from the top of the heap
[...]
This function cannot release free memory located at places other than the top of the heap.
当我现在查找malloc\u trim()
(在malloc/malloc.c中)的源代码时,我看到它调用了mtrim()
,它利用madvise(x,MADV\u DONTNEED)
将内存释放回操作系统
所以我想知道手册页是不是错了,或者我是否误解了malloc/malloc.c中的源代码
malloc\u trim()
能否从堆的中间释放内存
。。。利用madvise(x,MADV_DONTNEED)将内存释放回
操作系统
madvise(x,MADV\u DONTNEED)
不会释放内存<代码>曼德维塞:
不需要
不要期望在不久的将来访问。(暂时,
应用程序在给定范围内完成,因此内核
可以释放与之关联的资源。)的后续访问
此范围内的页面将成功,但将导致
从基础映射文件重新加载内存内容
(请参见mmap(2))或不带
底层文件
因此,madvise(x,MADV_DONTNEED)
的用法与man malloc_trim
的说法并不矛盾:
此函数无法释放位于堆顶部以外位置的可用内存
glibc中现在有两种
madvise
与MADV_DONTNEED
的用法:
Ulrich Drepper于2007年12月16日提交了以下文件(glibc 2.9及更新版本的一部分):
- malloc/malloc.c(public_mTRIm):迭代所有竞技场并调用
mTRIm
(现在)实施已更改。块的未使用部分,按页面大小对齐且大小大于页面大小,可标记为MADV_DONTNEED
:
/* 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);
在malloc/malloc.c中,从块中间释放的内容没有记录为文本(2007年,command中的malloc_trim
description没有更新),也没有记录在手册页项目中。2012年的手册页可能是该函数的第一个手册页,不是由glibc的作者编写的。glibc的信息页面仅提及128 KB的M_修剪_阈值:
不要列出malloc_trim函数(也不要记录memusage/memusagestat/libmemusage.so)
您可以像在“malloc_trim()behavior”中所做的那样,再次询问Drepper和其他glibc开发人员,但他们仍然没有回复。(只有来自其他用户的错误答案,如)
或者您可以使用这个简单的C程序(test\u malloc\u trim.C
)和strace
/ltrace
)测试malloc\u 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);
printf("1:%p 2:%p 3:%p 4:%p\n", m1, m2, m3, m4);
free(m2);
malloc_trim(0); // 20000, 2000000
sleep(1);
free(m1);
free(m3);
free(m4);
// malloc_stats(); malloc_info(0, stdout);
return 0;
}
<> P> > <代码> Mebug <代码> <代码> MavaDodoDodos<代码> 9页>代码> MalLogyTrimm(0)调用,当堆中间有40008个字节的孔时,文档中有没有?code>此函数无法释放堆顶部以外的其他位置的可用内存。@tangrs问题是,从实际实现来看,我认为文档是错误的(但我不太确定)。请始终听文档。函数的记录行为永远不会改变,但实现可以改变。依赖于使用特定实现的函数可能意味着您的程序将在未来版本或不同平台上崩溃。我关心特定实现的行为。在我的问题中,我说的是glibc。没有什么能阻止glibc版本之间的实现变化……关于madvise(x,MADV_DONTNEED)不释放内存。对给定范围调用此函数的结果是操作系统可以释放底层页面。提交到相应流程的页面将减少。对我来说,这归结为释放记忆相应流程中的映射将保持不变(尽管指向COW零页)。如果我的进程将新数据放在给定的范围内,内核将不得不提供一些支持这一点的页面(向我提交内存)。如果页面映射仍然存在,那么它们所代表的进程虚拟内存就没有真正释放,不是吗!进程没有从地址空间永久返回页面,因此没有“释放”它们。充其量,它告诉内核它的RSS可以减少,但它实际上并没有减少它的VSZIZE,所以它实际上并没有“发布”任何页面。理解“release”在heap和
malloc()
中的含义的关键在于,当它说它将“释放位于堆顶部的空闲内存”时,它意味着“它将减少VSIZE”。类似GNU的项目维护人员在手册页和其他文档中的典型官方位置:“Ulrich Drepper 2006-05-01手册页不在glibc中维护。告诉手册页维护人员。”
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
#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);
printf("1:%p 2:%p 3:%p 4:%p\n", m1, m2, m3, m4);
free(m2);
malloc_trim(0); // 20000, 2000000
sleep(1);
free(m1);
free(m3);
free(m4);
// malloc_stats(); malloc_info(0, stdout);
return 0;
}
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
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({1, 0}, 0x7ffffafbfff0) = 0
brk(0xceb000) = 0xceb000