glibcptmalloc內(nèi)存暴增問(wèn)題解決
glibcptmalloc內(nèi)存暴增問(wèn)題解決
;直接上代碼。#include ;<;stdio.h>。#include ;<;stdlib.h>。#include ;<;string.h>。int ;main()。{;int ;alloc_time ;= ;4000。char ;*a[alloc_time]。char ;*b[alloc_time]。int ;i, ;j。for(i=0; ;i<;alloc_time; ;i++)。{;a[i] ;= ;(char ;*)malloc(52722)。memset(a[i], ;1, ;52722)。
導(dǎo)讀 ;直接上代碼。#include ;<;stdio.h>。#include ;<;stdlib.h>。#include ;<;string.h>。int ;main()。{;int ;alloc_time ;= ;4000。char ;*a[alloc_time]。char ;*b[alloc_time]。int ;i, ;j。for(i=0; ;i<;alloc_time; ;i++)。{;a[i] ;= ;(char ;*)malloc(52722)。memset(a[i], ;1, ;52722)。
系統(tǒng)大全為您提供?直接上代碼:#include?
#include?#include?int?main(){int?alloc_time?=?4000;char?*a[alloc_time];char?*b[alloc_time];int?i,?j;for(i=0;?i=0;?i--){free(a[i]);free(b[i]);}printf("free?finished");/ar?*p?=?(char?*)malloc(2000);//free(p);while(1){sleep(3);}}運(yùn)行這個(gè)測(cè)試程序,發(fā)現(xiàn)Glibc內(nèi)存暴增,程序已經(jīng)把內(nèi)存返回給了Glibc庫(kù),但Glibc庫(kù)卻沒(méi)有把內(nèi)存歸還給操作系統(tǒng)。分析:ptmalloc使用chunk結(jié)構(gòu)來(lái)實(shí)現(xiàn)內(nèi)存管理。用戶(hù)free掉的內(nèi)存并不是都會(huì)馬上歸還給系統(tǒng),ptmalloc會(huì)統(tǒng)一管理heap和mmap映射區(qū)域中的空閑chunk.當(dāng)用戶(hù)進(jìn)行下一次分配請(qǐng)求時(shí),ptmalloc會(huì)首先試圖在空閑的chunk中挑選一塊給用戶(hù),這樣就避免了頻繁的系統(tǒng)調(diào)用,降低了內(nèi)存分配的開(kāi)銷(xiāo)。對(duì)于空閑的chunk,ptmalloc采用分箱式內(nèi)存管理方式,根據(jù)空閑chunk的大小和處于的狀態(tài)將其放在三個(gè)不同的容器中。bins:ptmalloc將相似大小的chunk用雙向鏈表鏈接起來(lái),這樣的一個(gè)鏈表被稱(chēng)為一個(gè)bin.bins有128個(gè)隊(duì)列,前64個(gè)隊(duì)列是定長(zhǎng)的(small?bins),每隔8個(gè)字節(jié)大小的塊分配在一個(gè)隊(duì)列,后面的64個(gè)隊(duì)列是不定長(zhǎng)的(large?bins),就是在一個(gè)范圍長(zhǎng)度的都分配在一個(gè)隊(duì)列中。所有長(zhǎng)度小于512字節(jié)的都分配在定長(zhǎng)的隊(duì)列中,后面的64個(gè)隊(duì)列是變長(zhǎng)的隊(duì)列,每個(gè)隊(duì)列中的chunk都是從大到小排列的。unsort隊(duì)列(只有一個(gè)隊(duì)列),它是一個(gè)cache,所有free下來(lái)的如果要進(jìn)入bins隊(duì)列中都要經(jīng)過(guò)unsort隊(duì)列,分配內(nèi)存時(shí)會(huì)查看unsorted?bin中是否有合適的chunk,如果找到滿足條件的chunk,則直接返回給用戶(hù),否則將unsorted?bin中所有chunk放入bins中。fastbins,大約有10個(gè)定長(zhǎng)隊(duì)列,它是一個(gè)高速緩沖,所有free下來(lái)的并且長(zhǎng)度是小于max_fast(默認(rèn)80B)的chunk就會(huì)進(jìn)入這種隊(duì)列中。進(jìn)入此隊(duì)列的chunk在free的時(shí)候并不修改使用位,目的是為了避免被相鄰的塊合并掉。如果內(nèi)存塊是空閑的,它會(huì)掛在其中的一個(gè)隊(duì)列中,它是通過(guò)復(fù)用的方式,使用空閑chunk的第3個(gè)字和第4個(gè)字當(dāng)作它的前鏈和后鏈(變長(zhǎng)塊是第5個(gè)字和第6個(gè)字)。malloc的步驟:1.?先在fastbins中找,如果能找到,從隊(duì)列中取下后(不需要再置使用位為1)立刻返回;2.?判斷需求的塊是否在small?bins(bins的前64個(gè)bin)范圍,如果在小箱子范圍,并且剛好有滿足需求的塊,則直接返回內(nèi)存地址;3.?到了這一步,說(shuō)明需要分配的是一塊大內(nèi)存,或者小箱子里找不到合適的chunk;這個(gè)時(shí)候,會(huì)觸發(fā)consolidate,ptmalloc首先會(huì)遍歷fastbins中的chunk,將相鄰的chunk合并,并鏈接到unsorted?bin中(因?yàn)樵诖笙渥诱乙话愣家懈睿砸獌?yōu)先合并,避免過(guò)多碎片);4.?在unsort?bin中取出一個(gè)chunk,如果能找到剛好和想要的chunk相同大小的chunk,立刻返回,如果不是想要的chunk大小的chunk,就把它插入到bins對(duì)應(yīng)的隊(duì)列中去,轉(zhuǎn)到2.5.?到了這一步,說(shuō)明需要分配的是一塊大的內(nèi)存,或者small?bins和unsorted?bin中都找不到合適的chunk,并且fastbins和unsorted?bin中所有的chunk都清楚干凈了。在large?bins中找,找到一個(gè)最小的能符合需求的chunk從隊(duì)列中取下,如果剩下的大小還能建一個(gè)chunk,就把chunk分成兩個(gè)部分,把剩下的chunk插入到unsort隊(duì)列中取,把chunk的內(nèi)存地址返回;6.?如果搜索fastbins和bins都沒(méi)有找到合適的chunk,那么就需要操作topchunk(是堆頂?shù)囊粋€(gè)chunk,不會(huì)放在任何一個(gè)隊(duì)列里)來(lái)進(jìn)行分配了。在topchunk找,如果能切出符合要求的,把剩下的一部分當(dāng)作topchunk,然后返回內(nèi)存地址;7.?到了這一步說(shuō)明topchunk也不能滿足分配要求,就只能調(diào)用sysalloc,其實(shí)就是增長(zhǎng)堆了,然后返回內(nèi)存地址。free的步驟:1.?判斷所需釋放的chunk是否為mmaped?chunk,如果是,則調(diào)用munmap釋放mmaped?chunk,解除內(nèi)存空間映射,該空間不再有效,然后立刻返回;2.?如果和topchunk相鄰,直接和topchunk合并,不會(huì)放到其他的空閑隊(duì)列中取,然后立刻返回;3.?如果釋放的大小小于max_fast(80字節(jié)),就把它掛到fastbins中去返回,使用位仍然為1,當(dāng)然更不會(huì)去合并相鄰塊,然后立刻返回;4.?如果釋放塊得大小介于80-128K,把chunk的使用位置為0,判斷前一個(gè)chunk是否處于使用中,如果前一塊也是空閑塊,則合并,并轉(zhuǎn)入下一步;5.?判斷當(dāng)前釋放chunk的下一個(gè)塊是否為top?chunk,如果是,則轉(zhuǎn)到第7步,否則轉(zhuǎn)下一步;6.?判斷下一個(gè)chunk是否處在使用中,如果也是空閑的,則合并,并將合并后的chunk掛到unsort隊(duì)列中去;7.?如果執(zhí)行到了這一步,說(shuō)明釋放了一個(gè)與top?chunk相鄰的chunk;則無(wú)論它有多大,都將它與top?chunk合并,并更新top?chunk的大小等信息,轉(zhuǎn)下一步;8.?如果合并后的大小大于FASTBIN_CONSOLIDATION_THRESHOLD(64K),也會(huì)觸發(fā)consolidate,即fastbins的合并操作,合并后的chunk會(huì)被放到unsorted?bin中,fastbins將變?yōu)榭眨僮魍瓿芍筠D(zhuǎn)下一步;9.?試圖收縮堆。(判斷topchunk的大小是否大于mmap的收縮閾值,默認(rèn)為128KB)。ptmalloc對(duì)于大于128K的塊通過(guò)mmap方式來(lái)分配,小于128K(mmap分配閾值)的塊在heap中分配。堆是通過(guò)brk的方式來(lái)增加或壓縮的,如果在現(xiàn)有的堆中不能找到合適的chunk,會(huì)通過(guò)增長(zhǎng)堆的方式來(lái)滿足分配,如果堆頂?shù)目臻e塊超過(guò)一定的閾值會(huì)收縮堆,所以只要堆頂?shù)目臻g沒(méi)釋放,堆是一直不會(huì)收縮的。因?yàn)閜tmalloc的內(nèi)存收縮是從top?chunk開(kāi)始,如果與top?chunk(堆頂?shù)囊粋€(gè)chunk)相鄰的那個(gè)chunk在內(nèi)存池中沒(méi)有釋放,top?chunk以下的空閑內(nèi)存都無(wú)法返回給系統(tǒng),即使這些空閑內(nèi)存有幾十個(gè)G也不行。按照這個(gè)測(cè)試程序分配后,內(nèi)存變成由小塊和大塊交替出現(xiàn),釋放小塊的時(shí)候,直接把小塊放在fastbins中取,而且他的使用位還是1,釋放大塊的時(shí)候,它試圖合并相鄰的塊,但是和它相鄰的塊的使用位還是1,所以它不能把相鄰的塊合并起來(lái),而且釋放的塊的大小小于64K,也不會(huì)觸發(fā)consolidate,即不會(huì)把fastbins清空,所以當(dāng)所有的塊都被釋放完后,所有的小塊都在fastbins里面,使用位都還是1,大塊都掛在unsort隊(duì)列里面。全部都無(wú)法合并。所以使用的堆更加無(wú)法壓縮。如果在循環(huán)后面再分配2000字節(jié)然后釋放的話,所有內(nèi)存將全部被清空,這是因?yàn)樵偕暾?qǐng)2000字節(jié)的時(shí)候,由malloc的第二步,程序會(huì)先調(diào)用consolidate,即把所有的fastbins清空,同時(shí)把相鄰的塊合并起來(lái),等到所有的fastbins清空的時(shí)候,所有的塊也被合并起來(lái)了,然后調(diào)用free(2000)的時(shí)候,這塊將被合并起來(lái),成為topchunk,并且大小遠(yuǎn)小于64K,所有堆將會(huì)壓縮,內(nèi)存歸還給系統(tǒng)。解決方法:減小mmap分配閾值,對(duì)于大內(nèi)存塊分配盡量采用mamp系統(tǒng)調(diào)用直接向操作系統(tǒng)分配,回收時(shí)用munmap返回給操作系統(tǒng)。但是這種做法會(huì)降低ptmalloc的分配釋放效率,因?yàn)橄到y(tǒng)調(diào)用mamp是串行的,操作系統(tǒng)需要對(duì)mmap分配內(nèi)存加鎖,而且操作系統(tǒng)對(duì)mmap的物理頁(yè)強(qiáng)制清0很慢。這個(gè)可以通過(guò)修改MALLOC_MMAP_THRESHOLD_環(huán)境變量或者調(diào)用mallopt()接口來(lái)實(shí)現(xiàn)。???以上就是系統(tǒng)大全給大家介紹的如何使的方法都有一定的了解了吧,好了,如果大家還想了解更多的資訊,那就趕緊點(diǎn)擊系統(tǒng)大全官網(wǎng)吧。??本文來(lái)自系統(tǒng)大全http:///如需轉(zhuǎn)載請(qǐng)注明!推薦:win7純凈版
glibcptmalloc內(nèi)存暴增問(wèn)題解決
;直接上代碼。#include ;<;stdio.h>。#include ;<;stdlib.h>。#include ;<;string.h>。int ;main()。{;int ;alloc_time ;= ;4000。char ;*a[alloc_time]。char ;*b[alloc_time]。int ;i, ;j。for(i=0; ;i<;alloc_time; ;i++)。{;a[i] ;= ;(char ;*)malloc(52722)。memset(a[i], ;1, ;52722)。
為你推薦