分类: 其他平台
2013-05-11 17:32:20
最近准备把jemalloc用到JVM中,就研究了一下它的源码,网上没有找到太多详细的资料,不像glibc的内存管理模块ptmalloc华庭写过一个很详细的文档。
首先介绍一下jemalloc中的几个核心概念:
1.arena。jemalloc的核心分配管理区域,对于多核系统,会默认分配4*cores的Arena,线程采取轮询的方式来选择相应的arena来进行内存分配。
2.chunk。具体进行内存分配的区域,目前的默认大小是4M。chunk以page(默认为4K)为单位进行管理,每个chunk的前几个page(默认是6个)用于存储后面所有page的状态,比如是否待分配还是已经分配;而后面的所有page则用于进行实际的分配。
3.bin。用来管理各个不同大小单元的分配,比如最小的Bin管理的是8字节的分配,每个Bin管理的大小都不一样,依次递增。jemalloc的bin和ptmalloc的bin的作用类似。
4.run。每个bin在实际上是通过对它对应的正在运行的Run进行操作来进行分配的,一个run实际上就是chunk里的一块区域,大小是page的整数倍,具体由实际的bin来决定,比如8字节的bin对应的run就只有1个page,可以从里面选取一个8字节的块进行分配。在run的最开头会存储着这个run的信息,比如还有多少个块可供分配。
5.tcache。线程对应的私有缓存空间,默认是使用的。因此在分配内存时首先从tcache中找,miss的情况下才会进入一般的分配流程。
接下来介绍它们之间的关系。每个arena有一个bin数组,根据机器配置不同它的具体结构也不同,由相应的size_class.h中的宏定义决定,在笔者的机器上这个bin数组会管理从8字节一直到3584字节共28种大小的bin,而每个bin会通过它对应的正在运行的run进行操作来进行分配的。每个tcahe有一个对应的arena,它本身也有一个bin数组(称为tbin),前面的部分与arena的bin数组是对应的,但它长度更大一些,因为它会缓存一些更大的块;而且它也没有对应的run的概念,因为它只做缓存,rnny它只有一个avail数组来存储被缓存的空间的地址。像笔者机器上的tcahe在arena最大的3584字节的bin的基础上,后面还有8个bin,分别对应4K,8K,12K一直到32K。
这里想重点介绍一下chunk与run的关系。之前提到chunk默认是4M,而run是在chunk中进行实际分配的操作对象,每次有新的分配请求时一旦tcache无法满足要求,就要通过run进行操作,如果没有对应的run存在就要新建一个,哪怕只分配一个块,比如只申请一个8字节的块,也会生成一个大小为一个page(默认4K)的run;再申请一个16字节的块,又会生成一个大小为4096字节的run。run的具体大小由它对应的bin决定,但一定是page的整数倍。因此实际上每个chunk就被分成了一个个的run。
可能说到这里读者还是十分模糊,那接下来就介绍一下jemalloc具体是如何进行内存分配的,具体流程如下:
参考资料:
1. jemalloc 3.0.0源码