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字段,剩下的便是可以使用的数据长度。

相关内容

热门资讯

激发暑期文旅消费新动能   内蒙古阿尔山,漫步国家森林公园,感受清凉夏日;甘肃敦煌,坐在鸣沙山上,听一场星空演唱会;江苏连云...
日股收跌0.19% 格隆汇7月11日|日经225指数收盘下跌76.68点,跌幅0.19%,报39569.68点。
遵义小伙跳水救人牺牲,年仅31... (转自:遵义晚报)7月8日下午6时,遵义市播州区出现感人一幕——尚嵇镇大坝社区全军坝组28岁的村民陈...
“小记者”走进河北省邯郸市食品... 中国质量新闻网讯 7月7日下午,河北省邯郸市食品药品检验中心(市食品药品安全科普基地)联合邯郸新闻传...
局地超42℃!下周河南持续高温... 大范围高温闷热天气强势来袭!12日起,西太平洋副热带高压将再次控制我省,受其影响,13日至20日我省...
毕市监处罚[2025]1021... 毕市监处罚[2025]1021号浏览:1次基本信息:处罚机关毕节市市场监督管理局处罚日期2025年0...
达势股份-达美乐中国以4D战略...   达势股份-达美乐中国("达美乐中国"或"达势股份"或"公司")(1405.HK)是达美乐比萨在中...
“向上取整”:变相“明抢” 转自:中国质量报□ 胡立彪近日,有媒体对快递行业称重计费问题进行测评,结果发现,被测评的8家快递企业...
以改革破局 盐城经开区多点突破... 中新网江苏新闻7月11日电(倪玲)改革是发展的根本动力,开放是进步的必由之路。近年来,盐城经开区将推...
中国代表强调国际刑事法院应依法... 转自:千龙网新华社联合国7月10日电 中国常驻联合国副代表孙磊10日在安理会审议国际刑事法院涉苏丹问...