jemalloc源码解读(四)长度对齐算法

来源:互联网 发布:python 面向对象 pdf 编辑:程序博客网 时间:2024/05/17 03:37

    在现代计算架构中,从内存中读取数据,基本上都是按2^N个字节来从主存加载CPU中。这个值,基本是cache line的大小。也就是说,如果一块内存是是在同一块cache line之内是最快的。目前来说,多数PC的cache line值是128个字节。 对于首地址也是一样的。在32位机器上,如果有4个字节的内存块,跨2个cache line,那么被加载到CPU的时候,需要2次内存缺失中断。

   好了,言归正传。对于任何一种小内存请求,都不会按实际大小分配,首先会按照一定规则进行对齐。这种对齐的规则比较复杂,一般会依照系统页大小,机器字大小,和系统特性来定制。通常来说,会在不同区间采用不同的步长。举个例子:

序号大小区间字节对齐0[0--16]81(16 , 128]162(128 , 256]323(256 , 512]64

由于每个区间的步长不一样,又被划分成更多的区间。比如(256 , 320]之间长度请求,实际被分配应该是320个字节,而不是512。而1个字节的请求,总是被分配8个字节。


对于任意一个请求Size,为了快速得到他实际应该要被分配的实际长度。这个已经很难通过算法来完成了,因为这个区间的划分有一定不确定性,需要根据经验值来 调整。在jemalloc和tcmalloc他们都采用同样的算法,就是二次查表法。首先建立两个数组 size_to_index和 class_to_size ,size_to_index保存class_to_size的下标,而class_to_size保存对齐后的长度。从jemalloc的size_classes.h和arena.h中挖了一段代码出来,稍微修改后,如下:

typedef unsigned char uint8_t ;#defineSIZE_CLASSES\    SIZE_CLASS(0,8,8)\    SIZE_CLASS(1,8,16)\    SIZE_CLASS(2,16,32)\    SIZE_CLASS(3,16,48)\    SIZE_CLASS(4,16,64)\    SIZE_CLASS(5,16,80)\    SIZE_CLASS(6,16,96)\    SIZE_CLASS(7,16,112)\    SIZE_CLASS(8,16,128)\    SIZE_CLASS(9,32,160)\    SIZE_CLASS(10,32,192)\    SIZE_CLASS(11,32,224)\    SIZE_CLASS(12,32,256)\    SIZE_CLASS(13,64,320)\    SIZE_CLASS(14,64,384)\    SIZE_CLASS(15,64,448)\    SIZE_CLASS(16,64,512)\    SIZE_CLASS(17,128,640)\    SIZE_CLASS(18,128,768)\    SIZE_CLASS(19,128,896)\    SIZE_CLASS(20,128,1024)\    SIZE_CLASS(21,256,1280)\    SIZE_CLASS(22,256,1536)\    SIZE_CLASS(23,256,1792)\    SIZE_CLASS(24,256,2048)\    SIZE_CLASS(25,512,2560)\    SIZE_CLASS(26,512,3072)\    SIZE_CLASS(27,512,3584)\#defineNBINS28#defineSMALL_MAXCLASS3584const uint8_tsmall_size2bin[] = {#defineS2B_8(i)i,#defineS2B_16(i)S2B_8(i) S2B_8(i)#defineS2B_32(i)S2B_16(i) S2B_16(i)#defineS2B_64(i)S2B_32(i) S2B_32(i)#defineS2B_128(i)S2B_64(i) S2B_64(i)#defineS2B_256(i)S2B_128(i) S2B_128(i)#defineS2B_512(i)S2B_256(i) S2B_256(i)#defineS2B_1024(i)S2B_512(i) S2B_512(i)#defineS2B_2048(i)S2B_1024(i) S2B_1024(i)#defineS2B_4096(i)S2B_2048(i) S2B_2048(i)#defineS2B_8192(i)S2B_4096(i) S2B_4096(i)#defineSIZE_CLASS(bin, delta, size)\S2B_##delta(bin)SIZE_CLASSES#undef S2B_8#undef S2B_16#undef S2B_32#undef S2B_64#undef S2B_128#undef S2B_256#undef S2B_512#undef S2B_1024#undef S2B_2048#undef S2B_4096#undef S2B_8192#undef SIZE_CLASS};typedef struct __arena_bin_info_t{    size_t reg_size ;} arena_bin_info_t ;arena_bin_info_tarena_bin_info[NBINS];void bin_info_init(void){arena_bin_info_t *bin_info;size_t prev_run_size = 4096;#defineSIZE_CLASS(bin, delta, size)\bin_info = &arena_bin_info[bin];\bin_info->reg_size = size;SIZE_CLASSES#undef SIZE_CLASS}void test_size_class() {    FILE * file = fopen("small_size2bin.txt" , "w+b") ;    size_t size = sizeof(small_size2bin) ;    fprintf(file , "sizeof[small_size2bin] = %u \n" , size) ;    for(size_t idx = 0 ; idx < size ; ++idx)    {        fprintf(file , "idx[%u] , value[%hhu] \n" , idx , small_size2bin[idx]) ;        }    fclose(file) ;}void test_reg_size() {    memset(arena_bin_info , 0 , sizeof(arena_bin_info)) ;    bin_info_init() ;    FILE * file = fopen("arena_bin_info.txt" , "w+b") ;    size_t size = sizeof(arena_bin_info) ;    fprintf(file , "sizeof[arena_bin_info] = %u , count[%u]\n" , size , NBINS) ;    for(size_t idx = 0 ; idx < NBINS ; ++idx)    {        fprintf(file , "idx[%u] , reg_size[%hhu] \n" , idx , arena_bin_info[idx].reg_size) ;     }    fclose(file) ;}

代码中的数组small_size2bin等价于 size_to_index,arena_bin_info数组等价于class_to_size。

依据这两个数据,对于任何一个长度,要得到对应的对齐长度,就很简单了,如下:


size_t align(size_t size){    return arena_bin_info[size_to_index[size >> 3]] ;}

这个算法是一致的,但是建立class_to_size和size_to_index结果的算法,却不一样。jemalloc用宏的方式,显示指定每个区间的步长的。tcmalloc的算法比较先进,下面是他的算法,详细参见gperftools的common.cc文件的AlignmentForSize函数:

1、如果Size > MaxSize,那么就以PageSize对齐

2、如果Size >= 128 ,从32开始,以2的倍数,增长步长。如下表

序号区间步长0[128 --> 256)321[256 --> 512)642[512 --> 1024)1283[1024 --> 2048)2564[2048 --> 4096)5125[4096 --> 8192)10246[8192 --> 16384)20487[16384 --> 32768)40968[32768 --> 65536)81929[65536 --> 131072)1638410[131072 --> 262144)32768

这种算法见LgFloor函数,他的主要原则就是保证内存浪费利率控制1/8。因此,步长/区间上限=1/8。


3、如果Size >= 16,那么按16对齐

4、小于16就按8对齐。






原创粉丝点击