一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

探究操作系統(tǒng)的內(nèi)存分配(malloc)對(duì)齊策略

 西北望msm66g9f 2016-12-16

來自: 大熊先生_博客園

鏈接:http://www.cnblogs.com/Creator/archive/2012/04/05/2433386.html(點(diǎn)擊尾部閱讀原文前往)


問題:


我們?cè)趯懗绦虻臅r(shí)候經(jīng)常發(fā)現(xiàn)程序使用的內(nèi)存往往比我們申請(qǐng)的多,為了優(yōu)化程序的內(nèi)存占用,攪盡腦汁想要優(yōu)化內(nèi)存占用,可是發(fā)現(xiàn)自己的代碼也無從優(yōu)化了,怎么辦?現(xiàn)在我們把我們的焦點(diǎn)放到malloc上,畢竟我們向系統(tǒng)申請(qǐng)的內(nèi)存都是通過它完成了,不了解他,也就不能徹底的優(yōu)化內(nèi)存占用。


來個(gè)小例子

//g++ -o malloc_addr_vec  mallc_addr_vec.cpp 編譯  
#include  
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) {}//此時(shí)查看內(nèi)存占用      return 0;   }


 本文的測(cè)試環(huán)境為Linux 64Bit ,使用G++編譯為可執(zhí)行文件后,使用不同的啟動(dòng)參數(shù)啟動(dòng),使用top命令查看程序占用的內(nèi)存,這里我們主要是看RES指標(biāo)


RES  --  Resident size (kb)


The non-swapped physical memory a task has used.  


測(cè)試案例:


1、每次new 1 Byte   Do 1024*1024次


 ./malloc_addr_vec 1


啟動(dòng)程序后的內(nèi)存占用




內(nèi)存消耗 32MB 


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


 ./malloc_addr_vec 24


啟動(dòng)程序后的內(nèi)存占用



內(nèi)存消耗32MB 


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



/malloc_addr_vec 25


啟動(dòng)程序后的內(nèi)存占用 


內(nèi)存消耗48MB


為什么我們每次new 1Byte 和每次 new 24Byte系統(tǒng)消耗的內(nèi)存一樣呢?,為什么每次new 25Byte和 每次new 24Byte占用的內(nèi)存完全不同呢?


不知道大家在寫程序的時(shí)候有沒有關(guān)注過這個(gè)問題。我一次遇到時(shí),吐槽一句:What the fuck malloc. 


原因分析:


在大多數(shù)情況下,編譯器和C庫透明地幫你處理對(duì)齊問題。POSIX 標(biāo)明了通過malloc( ), calloc( ), 和 realloc( ) 返回的地址對(duì)于任何的C類型來說都是對(duì)齊的。


對(duì)齊參數(shù)(MALLOC_ALIGNMENT) 大小的設(shè)定并需滿足兩個(gè)特性


 1、必須是2的冪

 2、必須是(void *)的整數(shù)倍


至于為什么會(huì)要求是(void *)的整數(shù)倍,這個(gè)目前我還不太清楚,等你來發(fā)現(xiàn)...


根據(jù)這個(gè)原理,在32位和64位的對(duì)齊單位分別為8字節(jié)和16字節(jié)


但是這并解釋不了上面的測(cè)試結(jié)果,這是因?yàn)橄到y(tǒng)malloc分配的最小單位(MINSIZE)并不是對(duì)齊單位


為了進(jìn)一步了解細(xì)節(jié),從GNU網(wǎng)站中把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)="" &="">

其中request2size這個(gè)宏就是glibc的內(nèi)存對(duì)齊操作,MINSIZE就是使用malloc時(shí)占用內(nèi)存的最小單位。根據(jù)宏定義可推算在32位系統(tǒng)中MINSIZE為16字節(jié),在64位系統(tǒng)中MINSIZE一般為32字節(jié)。從request2size還可以知道,如果是64位系統(tǒng),申請(qǐng)內(nèi)存為1~24字節(jié)時(shí),系統(tǒng)內(nèi)存消耗32字節(jié),當(dāng)申請(qǐng)內(nèi)存為25字節(jié)時(shí),系統(tǒng)內(nèi)存消耗48字節(jié)。 如果是32位系統(tǒng),申請(qǐng)內(nèi)存為1~12字節(jié)時(shí),系統(tǒng)內(nèi)存消耗16字節(jié),當(dāng)申請(qǐng)內(nèi)存為13字節(jié)時(shí),系統(tǒng)內(nèi)存消耗24字節(jié)。 


一般他們的差距是一個(gè)指針大小,計(jì)算公式是


max(MINSIZE,in_use_size) 


其中in_use_size=(要求大小+2*指針大小-指針大小)align to MALLOC_ALIGNMENT


(對(duì)于上面計(jì)算的由來可以參見glibc 內(nèi)存池管理 ptmalloc這篇文章的第4節(jié)chuck部分以及搜一下malloc的內(nèi)部實(shí)現(xiàn)源碼 )


為了證明這個(gè)理論的正確性,我們需要計(jì)算一次malloc到底花掉了多少內(nèi)存,我們用如下代碼分別在32bit Linux和 64bit Linux上做測(cè)試

#include  
#include  
int main()   {          char * p1;          char * p2;          int i=1;          printf('%d\n',sizeof(char *));          for(;i100;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();   }


其測(cè)試結(jié)果如下:


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

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的內(nèi)存對(duì)其原理后,對(duì)于程序的內(nèi)存占用的優(yōu)化又有了有的放矢。我們可以根據(jù)內(nèi)存對(duì)齊的原則來請(qǐng)求內(nèi)存,來制作我們的高效內(nèi)存池,從而避免隱形的資源浪費(fèi).


例如,目前STL的內(nèi)存池是以8Byte為對(duì)齊單位,內(nèi)存池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內(nèi)存池在發(fā)現(xiàn)某個(gè)規(guī)則的內(nèi)存用完了時(shí),會(huì)進(jìn)行refill,在進(jìn)行chunk_alloc


例如8Byte大小的空間沒有了,調(diào)用refill,refill會(huì)將其空間準(zhǔn)備20個(gè),也就是20*8,當(dāng)然refill做不了內(nèi)存分配,他把20個(gè)8Byte的需求提交給chunk_alloc 


chunk_alloc 能真正分配內(nèi)存,但是它分配的時(shí)候會(huì)將內(nèi)存空間*2,所以最終malloc的內(nèi)存為8*20*2=320 ,32bit系統(tǒng)給malloc的內(nèi)存為328,64bit系統(tǒng)給malloc的內(nèi)存為336


在32位和64位操作系統(tǒng)分別浪費(fèi)掉8Byte和16Byte,其實(shí)我們可以在chunk_alloc內(nèi)部簡(jiǎn)單的計(jì)算一下系統(tǒng)的內(nèi)存對(duì)齊,達(dá)到 chunk_alloc 級(jí)零浪費(fèi)...


至于 allocate級(jí)別的浪費(fèi),我想是避免不了了,譬如,我需要一個(gè)6Byte的空間,STL內(nèi)存池給我的確實(shí)8Byte



●本文編號(hào)82,以后想閱讀這篇文章直接輸入82即可。

●輸入m可以獲取到文章目錄


推薦15個(gè)技術(shù)類公眾微信

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    亚洲二区欧美一区二区| 色婷婷视频免费在线观看| 国产精品香蕉免费手机视频| 国产一区在线免费国产一区| 性欧美唯美尤物另类视频| 五月婷日韩中文字幕四虎| 一区二区三区免费公开| 国产精品不卡一区二区三区四区| 国产亚洲欧美日韩精品一区| 亚洲少妇人妻一区二区| 亚洲中文字幕熟女丝袜久久| 国产色一区二区三区精品视频| 天海翼高清二区三区在线| 国产免费人成视频尤物| 亚洲国产综合久久天堂| 国产精品流白浆无遮挡| 亚洲日本韩国一区二区三区| 亚洲高清欧美中文字幕| 久久精品国产亚洲av久按摩| 中文字幕日韩一区二区不卡| 老鸭窝老鸭窝一区二区| 美女被后入视频在线观看| 日本一区二区三区黄色| 成年男女午夜久久久精品| 熟女乱一区二区三区丝袜| 日韩欧美一区二区不卡看片| 丰满熟女少妇一区二区三区| 国产三级不卡在线观看视频| 国产又大又黄又粗的黄色| 人妻精品一区二区三区视频免精| 高清不卡一卡二卡区在线| 国产精品一区二区三区欧美| 综合久综合久综合久久| 成年午夜在线免费视频| 在线一区二区免费的视频| 在线观看视频成人午夜| 草草视频福利在线观看| 搡老熟女老女人一区二区| 91熟女大屁股偷偷对白| 国产精品一区二区三区欧美| 日本丁香婷婷欧美激情|