探究OS的内存分配对齐策略
问题:我们在写程序的时候经常发现程序使用的内存往往比我们申请的多,为了优化程序的内存占用,搅尽脑汁想要优化内存占用,可是发现自己的代码也无从优化了,怎么办?现在我们把我们的焦点放到malloc上,毕竟我们向系统申请的内存都是通过它完成了,不了解他,也就不能彻底的优化内存占用。
来个小例子
//g++ -o malloc_addr_vec mallc_addr_vec.cpp 编译
2 #include<iostream>
3 using namespace std;
4 int main(int argc, char *argv[])
5 {
6 int malloc_size = atoi(argv[1]);
7 char * malloc_char;
8 for (size_t i = 0; i < 1024*1024; ++i) {
9 malloc_char = new char[malloc_size];
10 }
11 while (1) {}//此时查看内存占用
12 return 0;
13 }
本文的测试环境为Linux 64Bit ,使用G++编译为可执行文件后,使用不同的启动参数启动,使用top命令查看程序占用的内存,这里我们主要是看RES指标
RES -- Resident size (kb)
The non-swapped physical memory a task has used.
测试案例:
1.每次new 1 Byte Do 1024*1024次
./malloc_addr_vec 1
启动程序后的内存占用
内存消耗 32MB
2.每次new 24 Byte Do 1024*1024次
./malloc_addr_vec 24
启动程序后的内存占用
内存消耗32MB
3.每次new 25 Byte Do 1024*1024次
./malloc_addr_vec 25
启动程序后的内存占用
内存消耗48MB
为什么我们每次new 1Byte 和每次 new 24Byte系统消耗的内存一样呢?,为什么每次new 25Byte和 每次new 24Byte占用的内存完全不同呢?
不知道大家在写程序的时候有没有关注过这个问题。我一次遇到时,吐槽一句:What the 易做图 malloc.
原因分析:
在大多数情况下,编译器和C库透明地帮你处理对齐问题。POSIX 标明了通过malloc( ), calloc( ), 和 realloc( ) 返回的地址对于任何的C类型来说都是对齐的。
对齐参数(MALLOC_ALIGNMENT) 大小的设定并需满足两个特性
1.必须是2的幂
2.必须是(void *)的整数倍
至于为什么会要求是(void *)的整数倍,这个目前我还不太清楚,等你来发现...
根据这个原理,在32位和64位的对齐单位分别为8字节和16字节
但是这并解释不了上面的测试结果,这是因为系统malloc分配的最小单位(MINSIZE)并不是对齐单位
为了进一步了解细节,从GNU网站中把glibc源码下载下来,查看其 malloc.c文件
View Code
1 #ifndef INTERNAL_SIZE_T
2 #define INTERNAL_SIZE_T size_t
3 #endif
4 #define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
5 #ifndef MALLOC_ALIGNMENT
6 #define MALLOC_ALIGNMENT (2 * SIZE_SZ)
7 #endif
8
9
10 struct malloc_chunk {
11 INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
12 INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
13 struct malloc_chunk* fd; /* double links -- used only if free. */
14 struct malloc_chunk* bk;
15 };
16
17 An allocated chunk looks like this:
18 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19 | Size of previous chunk, if allocated | |
20 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21 | Size of chunk, in bytes |M|P|
22 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23 | User data starts here... .
24 . .
25 . (malloc_usable_size() bytes) .
26 . |
27 nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 | Size of chunk |
29 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30
31
32 #define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
33 #define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk))
34 #define MINSIZE /
35 (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
36 /* pad request bytes into a usable size -- internal version */
37 #define request2size(req) &nbs
补充:软件开发 , C++ ,