MALLOC_ARENA_MAX=1 与 MALLOC_ARENA_MAX=4有什么区别?

MALLOC_ARENA_MAX=1 与 MALLOC_ARENA_MAX=4有什么区别?

2019年 Elastic开发者大会的时候我曾经说过 glibc 导致的堆外内存过多问题:

如果应用程序每次分配内存的时候都通过系统调用 mmap,sbrk等来分配,效率会很低,所以glibc 中实现了一个内存池,应用程序使用内存的时候通过glibc的内存池来提供,早期的 glibc 版本中,只有一个内存池,称为 main arena,在多线程场景中,每次分配和释放需要进行加锁。后来为了降低锁的粒度,从glibc 2.10版本开始引入了 thread arena,线程在申请内存的时候,glibc 为他创建一个 thread arena,这个内存池的大小一般是64M,thread arena被不被某个线程独占,全部的 thread arena被加入到环形链表,被所有线程共享使用。

环境变量 MALLOC_ARENA_MAX 用来控制进程可以创建的 thread arena 数量上限(默认为 cpu core*8),在 Hadoop 中这个值设置为 4,军义兄发现要设置为1,否则控制不住,但是不清楚原因,按照常规的理解,既然这个参数可以生效,就应该准确地控制 arena 数量,和数值设置成多少没关系,查阅资料没有找到相关描述。近日一个 Hadoop 的 NameNode 占用内存比预期值多了40G,pmap 看一下,多出来的基本就是 64M 的 thread arena,查看进程当前的环境变量值:

确认为4,于是分析一下 MALLOC_ARENA_MAX 控制不住的原因。

这种情况通过简单的测试程序可以复现,看了一下 glibc 的相关代码,基本搞清楚了来龙去脉。

MALLOC_ARENA_MAX 控制不住的原因

如果 MALLOC_ARENA_MAX 设置为 n,当 n 个 thread arena 的内存空间全被占满的时候,线程新申请内存的时候优先创建新的 arena,不受 n 的限制,并且是无上限的。测试过程如下:

创建10个线程,每个线程申请64M 内存,不能直接 malloc 64M,因为glibc对于大块内存的申请直接 mmap

编译执行这个程序:

然后 pmap 查看进程内存空间:

标红的区域为进程创建的 thread arena,当配置的 n 个 thread arena空间不足时,glibc 有两种处理方式:

  • 创建新的 thread arena
  • 从 main arena 分配

绝大部分情况下,会创建新的 thread arena。

从实现上来说,arena_lookup查找分配区和 arena_lock锁分配区的时候并不关心该分配区的空间是否足够,如果 arena_lock 到的分配区空间不足,就创建新的thread arena
函数:sysmalloc

new_heap 创建新的 thread arena 时并不检查MALLOC_ARENA_MAX的配置值。

MALLOC_ARENA_MAX 可以生效的情况

与上面的结论相同,只有在thread arena没有被占满的情况下。为 MALLOC_ARENA_MAX设置的阈值可以控制住设定的数量。

将上面的测试程序修改为每个线程申请4M 内存,其他不变:

运行时参数不变,pmap 查看进程内存情况,共创建了3个 thread arena

为什么 MALLOC_ARENA_MAX 设置为1 能够控制住

当设置为1,相当于禁用了 thread arena,arena_lookup每次都会返回 main arena, 不会创建任何 thread arena

总结

当 glibc 的内存池空间不足时,优先创建thread arena进行分配。但是在内存释放的时候,又需要等待 top chunk释放掉,才能释放一个连续的空间给操作系统,造成 thread arena 存在非常多的一个主要原因是存在很多生命周期比较长的对象,如果这些对象能够及时释放,虽然进程可能会在短时间创建许多 thread arena,但实际上并不占据 RES,所以根本问题还是那些具有长生命周期的对象。

当只使用 main arena 的情况下,虽然具有长生命周期的对象不变,但是内存池中的空间被重用的几率比多个 thread arena 更高,进程占据的的 RES 要相对少一些。

参考

https://paper.seebug.org/papers/Archive/refs/heap/glibc内存管理ptmalloc源代码分析.pdf
http://pwn4.fun/2016/04/11/深入理解glibc-malloc/
https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/

(转载请注明作者和出处 easyice.cn ,请勿用于任何商业用途)

1 Star2 Stars3 Stars4 Stars5 Stars (1 人打了分, 平均分: 5.00 )
Loading...

2 thoughts on “MALLOC_ARENA_MAX=1 与 MALLOC_ARENA_MAX=4有什么区别?

  1. 非常意外地看到这篇文章,有几个问题请教下:
    1. 您使用的glibc版本是多少?
    2. 在实际项目中遇到一个问题,跟arena相关的。我使用的是2.17 157.el7_3.1,应用程序在并发线程数很多(如:1000甚至更多)时,内存持续上涨,而且不再下降,pmap结果感觉就是 arena内存没有释放。这是glibc现存的bug吗?

发表评论

邮箱地址不会被公开。 必填项已用*标注