理会操纵系统的内存分派(malloc)对齐计策
当前位置:以往代写 > C/C++ 教程 >理会操纵系统的内存分派(malloc)对齐计策
2019-06-13

理会操纵系统的内存分派(malloc)对齐计策

理会操纵系统的内存分派(malloc)对齐计策

副标题#e#

问题:

我们在写措施的时候常常发明措施利用的内存往往比我们申请的多,为了优化措施的内存占用,搅尽脑汁想要优化内存占用,但是发明本身的代码也无从优化了,怎么办?此刻我们把我们的核心放到malloc上,究竟我们向系统申请的内存都是通过它完成了,不相识他,也就不能彻底的优化内存占用。

来个小例子

//g++ -o malloc_addr_vec  mallc_addr_vec.cpp 编译  
#include<iostream>  
using namespace std;  
int main(int argc, char *argv[])  
{  
    int malloc_size = atoi(argv[1]);  
    char * malloc_char;  
    for (size_t i = 0; i < 1024*1024; ++i) {  
        malloc_char = new char[malloc_size];  
    }  
    while (1) {}//此时查察内存占用  
    return 0;  
}

本文的测试情况为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

启动措施后的内存占用

剖析哄骗系统的内存分配(malloc)对齐战略

内存耗损 32MB

2.每次new 24 Byte  Do 1024*1024次

./malloc_addr_vec 24

启动措施后的内存占用

剖析哄骗系统的内存分配(malloc)对齐战略

内存耗损32MB

3.每次new 25 Byte   Do 1024*1024次

./malloc_addr_vec 25

启动措施后的内存占用

剖析哄骗系统的内存分配(malloc)对齐战略

内存耗损48MB

为什么我们每次new 1Byte 和每次 new 24Byte系统耗损的内存一样呢?,为什么每次new 25Byte和 每次new 24Byte占用的内存完全差异呢?

不知道各人在写措施的时候有没有存眷过这个问题。我一次碰着时,吐槽一句:What the fuck malloc.


#p#副标题#e#

原因阐明:

在大大都环境下,编译器和C库透明地帮你处理惩罚对齐问题。POSIX 标明白通过malloc( ), calloc( ), 和 realloc( ) 返回的地点对付任何的C范例来说都是对齐的。

对齐参数(MALLOC_ALIGNMENT) 巨细的设定并需满意两个特性

1.必需是2的幂

2.必需是(void *)的整数倍

至于为什么会要求是(void *)的整数倍,这个今朝我还不太清楚,等你来发明…

按照这个道理,在32位和64位的对齐单元别离为8字节和16字节

可是这并表明不了上面的测试功效,这是因为系统malloc分派的最小单元(MINSIZE)并不是对齐单元

为了进一步相识细节,从GNU网站中把glibc源码下载下来,查察其malloc.c文件

#ifndef INTERNAL_SIZE_T    
#define INTERNAL_SIZE_T size_t    
#endif    
#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))    
#ifndef MALLOC_ALIGNMENT    
#define MALLOC_ALIGNMENT       (2 * SIZE_SZ)    
#endif    
      
      
struct malloc_chunk {    
  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */
  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;    
};    
      
    An allocated chunk looks like this:    
    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
            |             Size of previous chunk, if allocated            | |    
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
            |             Size of chunk, in bytes                       |M|P|    
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
            |             User data starts here...                          .    
            .                                                               .    
            .             (malloc_usable_size() bytes)                      .    
            .                                                               |    
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
            |             Size of chunk                                     |    
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
                  
                  
#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)    
#define MIN_CHUNK_SIZE        (sizeof(struct malloc_chunk))    
#define MINSIZE  /    
  (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))    
/* pad request bytes into a usable size -- internal version */
#define request2size(req)                                         /    
  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             /    
   MINSIZE :                                                      /    
   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

#p#分页标题#e#

个中request2size这个宏就是glibc的内存对齐操纵,MINSIZE就是利用malloc时占用内存的最小单元。按照宏界说可推算在32位系统中MINSIZE为16字节,在64位系统中MINSIZE 一般为32字节。从request2size还可以知道,假如是64位系统,申请内存为1~24字节时,系统内存耗损32字节,当申请内存为25字节时,系统内存耗损48字节。假如是32位系统,申请内存为1~12字节时,系统内存耗损16字节,当申请内存为13字节时,系统内存耗损24字节。

一般他们的差距是一个指针巨细,计较公式是

max(MINSIZE,in_use_size)

个中in_use_size=(要求巨细+2*指针巨细-指针巨细)align to MALLOC_ALIGNMENT

(对付上面计较的由来可以拜见glibc 内存池打点 ptmalloc这篇文章的第4节chuck部门以及搜一下malloc的内部实现源码 )

#p#副标题#e#

为了证明这个理论的正确性,我们需要计较一次malloc到底花掉了几多内存,我们用如下代码别离在32bit Linux和 64bit Linux上做测试

#include<stdio.h>  
#include<stdlib.h>  
int main()  
{  
        char * p1;  
        char * p2;  
        int i=1;  
        printf("%d\n",sizeof(char *));  
        for(;i<100;i++)  
        {  
                p1=NULL;  
                p2=NULL;  
                p1=(char *)malloc(i*sizeof(char));  
                p2=(char *)malloc(1*sizeof(char));  
                printf("i=%d     %d\n",i,(p2-p1));  
        }  
      
        getchar();  
}

其测试功效如下:

32bit

---------------------  
Linux  32bit  
---------------------   
4  
i=1 16  
i=2 16  
i=3 16  
i=4 16  
i=5 16  
i=6 16  
i=7 16  
i=8 16  
i=9 16  
i=10 16  
i=11 16  
i=12 16  
i=13 24  
i=14 24  
i=15 24  
i=16 24  
i=17 24  
i=18 24  
i=19 24  
i=20 24  
i=21 32  
i=22 32  
i=23 32  
i=24 32  
i=25 32  
i=26 32  
i=27 32  
i=28 32  
i=29 40  
i=30 40  
i=31 40  
i=32 40  
i=33 40  
i=34 40  
i=35 40  
i=36 40  
i=37 48  
i=38 48  
i=39 48  
i=40 48  
i=41 48  
i=42 48  
i=43 48  
i=44 48  
i=45 56  
i=46 56  
i=47 56  
i=48 56  
i=49 56  
i=50 56  
i=51 56  
i=52 56  
i=53 64  
i=54 64  
i=55 64  
i=56 64  
i=57 64  
i=58 64  
i=59 64  
i=60 64  
i=61 72  
i=62 72  
i=63 72  
i=64 72  
i=65 72  
i=66 72  
i=67 72  
i=68 72  
i=69 80  
i=70 80  
i=71 80  
i=72 80  
i=73 80  
i=74 80  
i=75 80  
i=76 80  
i=77 88  
i=78 88  
i=79 88  
i=80 88  
i=81 88  
i=82 88  
i=83 88  
i=84 88  
i=85 96  
i=86 96  
i=87 96  
i=88 96  
i=89 96  
i=90 96  
i=91 96  
i=92 96  
i=93 104  
i=94 104  
i=95 104  
i=96 104  
i=97 104  
i=98 104  
i=99 104

#p#副标题#e#

64bit

-------------------  
Linux  64bit  
-------------------   
8  
i=1 32  
i=2 32  
i=3 32  
i=4 32  
i=5 32  
i=6 32  
i=7 32  
i=8 32  
i=9 32  
i=10 32  
i=11 32  
i=12 32  
i=13 32  
i=14 32  
i=15 32  
i=16 32  
i=17 32  
i=18 32  
i=19 32  
i=20 32  
i=21 32  
i=22 32  
i=23 32  
i=24 32  
i=25 48  
i=26 48  
i=27 48  
i=28 48  
i=29 48  
i=30 48  
i=31 48  
i=32 48  
i=33 48  
i=34 48  
i=35 48  
i=36 48  
i=37 48  
i=38 48  
i=39 48  
i=40 48  
i=41 64  
i=42 64  
i=43 64  
i=44 64  
i=45 64  
i=46 64  
i=47 64  
i=48 64  
i=49 64  
i=50 64  
i=51 64  
i=52 64  
i=53 64  
i=54 64  
i=55 64  
i=56 64  
i=57 80  
i=58 80  
i=59 80  
i=60 80  
i=61 80  
i=62 80  
i=63 80  
i=64 80  
i=65 80  
i=66 80  
i=67 80  
i=68 80  
i=69 80  
i=70 80  
i=71 80  
i=72 80  
i=73 96  
i=74 96  
i=75 96  
i=76 96  
i=77 96  
i=78 96  
i=79 96  
i=80 96  
i=81 96  
i=82 96  
i=83 96  
i=84 96  
i=85 96  
i=86 96  
i=87 96  
i=88 96  
i=89 112  
i=90 112  
i=91 112  
i=92 112  
i=93 112  
i=94 112  
i=95 112  
i=96 112  
i=97 112  
i=98 112  
i=99 112

相识了malloc的内存对其道理后,对付措施的内存占用的优化又有了有的放矢。我们可以按照内存对齐的原则来请求内存,来建造我们的高效内存池,从而制止隐形的资源挥霍.

譬喻,今朝STL的内存池是以8Byte为对齐单元,内存池free_list巨细为

free_list[0] ——–> 8 byte

free_list[1] ——–> 16 byte

free_list[2] ——–> 24 byte

free_list[3] ——–> 32 byte

… …

free_list[15] ——-> 128 byte

STL内存池在发明某个法则的内存用完了时,会举办refill,在举办chunk_alloc

譬喻8Byte巨细的空间没有了,挪用refill,refill会将其空间筹备20个,也就是20*8,虽然refill做不了内存分派,他把20个8Byte的需求提交给chunk_alloc

chunk_alloc 能真正分派内存,可是它分派的时候会将内存空间*2,所以最终malloc的内存为8*20*2=320 ,32bit系统给malloc的内存为328,64bit系统给malloc的内存为336

在32位和64位操纵系统别离挥霍掉8Byte和16Byte,其实我们可以在chunk_alloc内部简朴的计较一下系统的内存对齐,到达 chunk_alloc 级零挥霍…

至于 allocate级此外挥霍,我想是制止不了了,譬如,我需要一个6Byte的空间,STL内存池给我简直实8Byte

作者:cnblogs 大熊(先生)

    关键字:

在线提交作业