Linux性能学习(2.3):内存_为什么分配的内存比申请的内存大16个字节
创始人
2024-05-28 21:28:15
0

文章目录

  • 1 验证申请不同内存,系统分配机制
    • 1.1 代码
    • 1.2 测试
    • 1.3 结论
  • 2 为什么会多分配内存
  • 3 为什么会有4字节不可使用

参考资料:

  1. https://www.gnu.org/software/libc/

在上一篇文章中,探讨了Linux系统对进程以及线程的内存分配问题,然后采用申请1KB内存的方式进行验证,然后发现将第二次申请的内存地址减去第一次申请内存的地址,长度为1040,比我们申请的1024多了16个字节,从而提出一个问题,“在64位系统中,为什么系统分配的内存比实际申请的内存大16个字节?”。

但是上一篇的文章主要是探讨内存分配的,所以对这个问题没有过多追究,提出这个问题也不严谨,因为只是申请了1024个字节,系统分配了1040,多了16个字节,那么如果申请1个字节、2个字节、3个字节等等,系统又是如何分配的,是否还是多分配16字节?64位系统和32位系统是否都是多分配16字节?

所以下面我们先验证下,如果我们申请不同大小的内存,系统是否还是会多申请16字节的内存?

1 验证申请不同内存,系统分配机制

1.1 代码

#include 
#include int main()
{int i = 0;char* s8New = NULL;char* s8Old = malloc(0);if (NULL == s8Old){printf("malloc err\n");}else{printf("malloc success, malloc size:%d, usable_size:%d, addr:%p, ", 0, malloc_usable_size(s8Old), s8Old);}for (i = 1; i < 20480; i++){	s8New = (char*)malloc(i);if (NULL == s8New){printf("malloc err\n");}if ((NULL != s8New) && (NULL !=  s8Old)){printf("addr size:%d\n", s8New - s8Old);s8Old = s8New;printf("malloc success, malloc size:%d, usable_size:%d, addr:%p, ", i, malloc_usable_size(s8Old), s8Old);}else{printf("malloc success, malloc size:%d, usable_size:%d, addr:%p, ", i, malloc_usable_size(s8New), s8New);}}return 0;
}

上述代码的功能是从1个字节开始,逐步增加,直到申请2MB的内存,查看系统分配情况,会有三个主要参数的打印:“malloc size”表示我们申请的内存,“usable_size”是使用malloc_usable_size来获取系统实际分配的大小,“addr size”为下一个申请的内存地址减去当前申请内存的地址,即为当前申请内存的大小。

1.2 测试

在Ubuntu 64位系统下测试,结果如下:
在这里插入图片描述

在32位系统下测试,结果如下:
在这里插入图片描述

上面的数据,只是部分数据,经过综合,得出如下数据:
64位系统
在这里插入图片描述

32位系统
在这里插入图片描述

1.3 结论

通过上面的表格,我们可以得出如下结论:

  • A.在我们申请内存的时候,系统可能会申请多的内存给到我们,具体规则是:
    32位系统下:N8+4,N为1~无穷大,(N8+4)的值为最接近与我们申请的内存的值;
    64位系统下:N16+8,N为1~无穷大,(N16+8)的值为最接近与我们申请的内存的值。
  • B.申请的内存的地址相减会比实际申请的内存usable_size还要大,在32位系统下大4个字节,在64位系统下大8个字节。即实际分配的内存地址范围大小为:
    32位系统下:N8+8;
    64位系统下:N
    16+16。

2 为什么会多分配内存

针对上面的结论A,我们进行分析查找原因。

在上面我们使用malloc来申请内存,那么这些问题就跟malloc有关了,我们查看下malloc相关的代码,看看有啥收获。

源码可通过上面参考链接进行下载,在malloc.c/_int_malloc函数中,我们看到了checked_request2size函数,它的作用是将我们需要申请的字节大小转换为内部的大小,通过字节对齐等方式进行转换,来获取最小MINSIZE(最小可分配大小)的大小。
在这里插入图片描述

在这里,我们得到了一个信息MINSIZE,我们进到checked_request2size函数里面进行查看,
在这里插入图片描述

在checked_request2size中的request2size中我们可以看到,如果 (req) + SIZE_SZ + MALLOC_ALIGN_MASK的大小小于MINSIZE,那么就返回MINSIZE,如果大于,则进行对齐操作,再返回。
现在我们获取到结果宏参数:SIZE_SZ、MALLOC_ALIGN_MASK、MINSIZE

SIZE_SZ的大小通过代码追踪就是unsigned int的长度,在32位系统中就是4个字节;
MALLOC_ALIGN_MASK相关的定义如下:

/* The corresponding bit mask value.  */
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
/* MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.  Itmust be a power of two at least 2 * SIZE_SZ, even on machines forwhich smaller alignments would suffice. It may be defined as largerthan this though. Note however that code and data structures areoptimized for the case of 8-byte alignment.  */
#define MALLOC_ALIGNMENT (2 * SIZE_SZ < __alignof__ (long double) \? __alignof__ (long double) : 2 * SIZE_SZ)

可以得出,MALLOC_ALIGNMENT在32位系统中的长度为2*SIZE_SZ,即长度为8,那么MALLOC_ALIGN_MASK的长度就为7了。
MINSIZE的相关定义如下:

#define MINSIZE  \(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))

MIN_CHUNK_SIZE 展开如下:

#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
===》等价于
#define MIN_CHUNK_SIZE (size_t) & ((struct malloc_chunk*)NULL) -> fd_nextsize)

struct malloc_chunk的定义如下:

struct malloc_chunk {INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).  */INTERNAL_SIZE_T      mchunk_size;       /* Size in bytes, including overhead. */struct malloc_chunk* fd;         /* double links -- used only if free. */struct malloc_chunk* bk;/* Only used for large blocks: pointer to next larger size.  */struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */struct malloc_chunk* bk_nextsize;
};

所以上面代码的大致意思是,取malloc_chunk中fd_nextsize的地址,这样得到的地址就是这个成员在结构体中的首地址。所以这个结构体中,必须需要的是前4个,后面两个仅用于large blocks,所以在32位的系统中,这个结构体的大小为44=16字节,在64位上为84=32位,或者4+4+8+8=24位。
由此,可以得到:

#define MINSIZE =(((16+7) & ~7))=16。

至此,我们可以得出如下信息,在32位系统中,一些参数值如下:

SIZE_SZ 4
MALLOC_ALIGNMENT 2*4=8
MALLOC_ALIGN_MASK 8-1=7
MIN_CHUNK_SIZE 16
MINSIZE 16

那么request2size宏定义可以换算如下:

#define request2size(req)       (((req) + 4 + 7 < 16)  ? 16 :                                                       ((req) + 4 + 7) & ~7)

将上面1.2章节中32位申请的内存对照表和上面的request2size中进行对照,结论一致。

同理,在64位系统中,一些参数值如下:

SIZE_SZ 8
MALLOC_ALIGNMENT 2*8=16
MALLOC_ALIGN_MASK 16-1=15
MIN_CHUNK_SIZE 32
MINSIZE 32

至此,我们可以得出结论,当我们申请内存时候,系统会根据自身的机制分配大于我们申请的内存的大小,具体分配大小参考request2size进行确认。

3 为什么会有4字节不可使用

针对问题B进行分析,在上面,我们看到在32位系统中,addr size比实际可使用的内存大小usable_size大4个字节,为什么会有这4个字节的浪费,或者说不能使用?

在malloc.c中有如下解释:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上面的解释大致如下:
我们申请的chunk主要由Size of previous chunk + Size of chunk+user data等几部分构成的,chunk指针指向chunk开始的地方,mem指针是提供给用户的指针地址,从这个这个地址可以使用,进行读写等操作。
在这里插入图片描述

空闲的chunk是存储是双向循环链表中的,结构体是由 Size of previous chunk + Size of chunk+fd+bk等4部分组成的,参考下图:
在这里插入图片描述

上面的A/M/P三个参数:

  • P:如果P为0,表示前一个chunk为空闲,则prev_size中的值才有效,表示上一个空闲chunk的大小;如果P为1,则前一个chunk正在使用,prev_size无效。
  • M:如果为1,则是通过mmap方式分配的内存;如果为0,则是通过heap方式分配的内存。
  • A:为0表示主分区分配的内存;为1表示非主分配区分配的内存。

通过上图可以看到,一个chunk有head和foot,都是表示当前chunk大小,但是foot已经在next chunk了,即next chunk的Size of previous chunk ,同时为了提高chunk的有效载荷数据,Size of previous chunk 这个数据段也会用来存储数据,所以一个chunk可以由head+mem两部组成。而head的长度为SIZE_SZ的长度,即4个字节。

所以可以理解为,在32位系统下,linux申请的内存减去4个字节的长度,剩下的长度均为有效数据长度,即我们可以使用的长度。

同理,在64位系统下,linux申请的内存减去8个字节的chunk size字段,剩下的便是可以使用的数据长度。

相关内容

热门资讯

Python|位运算|数组|动... 目录 1、只出现一次的数字(位运算,数组) 示例 选项代...
张岱的人物生平 张岱的人物生平张岱(414年-484年),字景山,吴郡吴县(今江苏苏州)人。南朝齐大臣。祖父张敞,东...
西游西后传演员女人物 西游西后传演员女人物西游西后传演员女人物 孙悟空 六小龄童 唐僧 徐少华 ...
名人故事中贾岛作诗内容简介 名人故事中贾岛作诗内容简介有一次,贾岛骑驴闯了官道.他正琢磨着一句诗,名叫《题李凝幽居》全诗如下:闲...
和男朋友一起优秀的文案? 和男朋友一起优秀的文案?1.希望是惟一所有的人都共同享有的好处;一无所有的人,仍拥有希望。2.生活,...
戴玉手镯的好处 戴玉手镯好还是... 戴玉手镯的好处 戴玉手镯好还是碧玺好 女人戴玉?戴玉好还是碧玺好点佩戴手镯,以和田玉手镯为佳!相嫌滑...
依然什么意思? 依然什么意思?依然(汉语词语)依然,汉语词汇。拼音:yī    rán基本解释:副词,指照往常、依旧...
高尔基的散文诗 高尔基的散文诗《海燕》、《大学》、《母亲》、《童年》这些都是比较出名的一些代表作。
心在飞扬作者简介 心在飞扬作者简介心在飞扬作者简介如下。根据相关公开资料查询,心在飞扬是一位优秀的小说作者,他的小说作...
卡什坦卡的故事赏析? 卡什坦卡的故事赏析?讲了一只小狗的故事, 我也是近来才读到这篇小说. 作家对动物的拟人描写真是惟妙...
林绍涛为简艾拿绿豆糕是哪一集 林绍涛为简艾拿绿豆糕是哪一集第三十二集。 贾宽认为是阎帅间接导致刘映霞住了院,第二天上班,他按捺不...
小爱同学是女生吗小安同学什么意... 小爱同学是女生吗小安同学什么意思 小爱同学,小安同学说你是女生。小安是男的。
内分泌失调导致脸上长斑,怎么调... 内分泌失调导致脸上长斑,怎么调理内分泌失调导致脸上长斑,怎么调理先调理内分泌,去看中医吧,另外用好的...
《魔幻仙境》刺客,骑士人物属性... 《魔幻仙境》刺客,骑士人物属性加点魔幻仙境骑士2功1体质
很喜欢她,该怎么办? 很喜欢她,该怎么办?太冷静了!! 太理智了!爱情是需要冲劲的~不要考虑着考虑那~否则缘...
言情小说作家 言情小说作家我比较喜欢匪我思存的,很虐,很悲,还有梅子黄时雨,笙离,叶萱,还有安宁的《温暖的玄》 小...
两个以名人的名字命名的风景名胜... 两个以名人的名字命名的风景名胜?快太白楼,李白。尚志公园,赵尚志。
幼儿教育的代表人物及其著作 幼儿教育的代表人物及其著作卡尔威特的《卡尔威特的教育》,小卡尔威特,他儿子成了天才后写的《小卡尔威特...
海贼王中为什么说路飞打凯多靠霸... 海贼王中为什么说路飞打凯多靠霸气升级?凯多是靠霸气升级吗?因为之前刚到时确实打不过人家因为路飞的实力...
运气不好拜财神有用吗运气不好拜... 运气不好拜财神有用吗运气不好拜财神有没有用1、运气不好拜财神有用。2、拜财神上香前先点蜡烛,照亮人神...