gpt4 book ai didi

linux - 了解 glibc malloc 修剪

转载 作者:IT王子 更新时间:2023-10-29 00:31:35 28 4
gpt4 key购买 nike

我目前正在处理的一些程序消耗的内存比我认为的要多得多。所以我想了解 glibc malloc 修剪是如何工作的。我写了以下测试:

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

#define NUM_CHUNKS 1000000
#define CHUNCK_SIZE 100

int main()
{
// disable fast bins
mallopt(M_MXFAST, 0);

void** array = (void**)malloc(sizeof(void*) * NUM_CHUNKS);

// allocating memory
for(unsigned int i = 0; i < NUM_CHUNKS; i++)
{
array[i] = malloc(CHUNCK_SIZE);
}

// releasing memory ALMOST all memory
for(unsigned int i = 0; i < NUM_CHUNKS - 1 ; i++)
{
free(array[i]);
}

// when enabled memory consumption reduces
//int ret = malloc_trim(0);
//printf("ret=%d\n", ret);

malloc_stats();

sleep(100000);
}

测试输出(不调用 malloc_trim):

Arena 0:
system bytes = 112054272
in use bytes = 112
Total (incl. mmap):
system bytes = 120057856
in use bytes = 8003696
max mmap regions = 1
max mmap bytes = 8003584

尽管几乎所有内存都已释放,但此测试代码消耗的常驻内存比预期的要多得多:

[root@node0-b3]# ps aux | grep test
root 14662 1.8 0.4 129736 **118024** pts/10 S 20:19 0:00 ./test

过程图:

0245e000-08f3b000 rw-p 00000000 00:00 0                                  [heap]
Size: 109428 kB
Rss: 109376 kB
Pss: 109376 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 109376 kB
Referenced: 109376 kB
Anonymous: 109376 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac
7f1c60720000-7f1c60ec2000 rw-p 00000000 00:00 0
Size: 7816 kB
Rss: 7816 kB
Pss: 7816 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 7816 kB
Referenced: 7816 kB
Anonymous: 7816 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB

当我启用对 malloc_trim 的调用时,测试的输出几乎保持不变:

ret=1
Arena 0:
system bytes = 112001024
in use bytes = 112
Total (incl. mmap):
system bytes = 120004608
in use bytes = 8003696
max mmap regions = 1
max mmap bytes = 8003584

然而,RSS 明显下降:

[root@node0-b3]# ps aux | grep test
root 15733 0.6 0.0 129688 **8804** pts/10 S 20:20 0:00 ./test

处理 smap(在 malloc_trim 之后):

01698000-08168000 rw-p 00000000 00:00 0                                  [heap]
Size: 109376 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac
7f508122a000-7f50819cc000 rw-p 00000000 00:00 0
Size: 7816 kB
Rss: 7816 kB
Pss: 7816 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 7816 kB
Referenced: 7816 kB
Anonymous: 7816 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB

调用 malloc_trim 后,堆变小了。我假设 8MB mmap 段仍然可用,因为最后一 block 内存没有被释放。

为什么 malloc 不自动执行堆修剪?有没有办法配置 malloc 以便自动完成修剪(当它可以节省那么多内存时)?

我使用的是 glibc 2.17 版。

最佳答案

主要是出于历史原因,小分配的内存来自由 brk 管理的池系统调用。这是一个非常古老的系统调用——至少与Version 6 Unix一样古老— 它唯一能做的就是改变内存中位置固定的“竞技场”的大小。这意味着,brk 池不能缩小超过仍分配的 block 。

你的程序分配了 N 个内存块,然后释放了其中的 N-1 个。它不会释放的一个 block 是位于最高 地址的 block 。这是 brk 的最坏情况:即使 99.99% 的池未使用,大小也根本无法减少!如果您更改您的程序,使其未释放的 block 是 array[0] 而不是 array[NUM_CHUNKS-1],您应该同时看到 RSS 和地址空间在最后一次调用 free 时收缩。

当您显式调用 malloc_trim 时,它会尝试使用 Linux 扩展来解决此限制,madvise(MADV_DONTNEED) ,它会释放物理 RAM,但不会释放地址空间(正如您观察到的那样)。我不知道为什么这只会在显式调用 malloc_trim 时发生。

顺便说一句,8MB 的 mmap 段用于您初始分配 array

关于linux - 了解 glibc malloc 修剪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38644578/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com