Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux malloc_trim()能否从堆的中间释放内存?_Linux_Memory_Operating System_Malloc_Glibc - Fatal编程技术网

Linux 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中)的

我对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中)的源代码时,我看到它调用了
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适用于所有人。 (mTRIm):另外迭代所有空闲块并使用madvise 为所有包含至少一个数据块的数据块释放内存 内存页

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