日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

ptmalloc内存分配和回收详解(文字版)

發(fā)布時(shí)間:2023/12/1 编程问答 66 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ptmalloc内存分配和回收详解(文字版) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ptmalloc內(nèi)存分配和回收詳解(文字版)

進(jìn)程默認(rèn)內(nèi)存布局(x86)

從進(jìn)程的內(nèi)存布局可知,.bss段之上的這塊分配給用戶程序的空間被稱之為heap,start_brk指向heap的開始,而brk指向heap的頂部。可以使用系統(tǒng)調(diào)用brk()和sbrk()來增加表示heap頂部的brk值,從而線性的增加分配給用戶的heap空間。在使用malloc之前,brk的值等于start_brk,也就是說,heap大小為0。

ptmalloc在開始時(shí),若請(qǐng)求的空間小于mmap分配閾值(mmap threshold, 默認(rèn)值為128KB)時(shí),主分配區(qū)會(huì)調(diào)用sbrk()增加一塊大小為(128KB + chunk_size)align 4KB的空間作為heap,非主分配區(qū)會(huì)調(diào)用mmap映射一塊大小為HEAP_MAX_SIZE(32位1MB,64位64MB)的空間作為sub-heap。這就是ptmalloc所維護(hù)的分配空間。

ptmalloc內(nèi)存管理設(shè)計(jì)假設(shè)

1、具有長(zhǎng)生命周期的大內(nèi)存分配使用mmap。

2、特別大的內(nèi)存分配總是使用mmap。

3、具有短生命周期的內(nèi)存分配使用brk,因?yàn)橛胢map映射匿名頁(yè),當(dāng)發(fā)生缺頁(yè)異常時(shí),linux內(nèi)核為缺頁(yè)分配一個(gè)新的物理頁(yè),導(dǎo)致多次清零操作,很浪費(fèi)系統(tǒng)資源,所以引入了mmap分配閾值動(dòng)態(tài)調(diào)整機(jī)制,保證在必要的情況下才使用mmap分配內(nèi)存。

4、盡量只緩存臨時(shí)使用的空閑小內(nèi)存塊,對(duì)大內(nèi)存快或是長(zhǎng)生命周期的大內(nèi)存塊在釋放時(shí)都直接歸還給操作系統(tǒng)。

5、對(duì)空閑的小內(nèi)存塊只會(huì)在malloc和free的時(shí)候進(jìn)行合并,free時(shí)空閑內(nèi)存塊可能放入bin中,不一定歸還給操作系統(tǒng)。

6、收縮堆的條件是當(dāng)前free的塊大小加上前后能合并chunk的大小大于64KB,并且堆頂?shù)拇笮∵_(dá)到閾值,才有可能收縮堆,把堆最頂端的空閑內(nèi)存返回給操作系統(tǒng)。

7、需要長(zhǎng)期存儲(chǔ)的程序不適合用ptmalloc來管理內(nèi)存。

8、為了支持多線程,多個(gè)線程可以從同一個(gè)分配區(qū)中分配內(nèi)存,ptmalloc假設(shè)線程A釋放掉一塊內(nèi)存后,線程B會(huì)申請(qǐng)類似大小的內(nèi)存,但是A釋放的內(nèi)存跟B需要的內(nèi)存不一定完全相等,可能有稍許誤差,就需要不停的對(duì)內(nèi)存塊進(jìn)行切割和合并,這個(gè)過程可能產(chǎn)生內(nèi)存碎片。

內(nèi)存分配

1、獲取分配區(qū)的鎖,為了防止多個(gè)線程同時(shí)訪問同一個(gè)分配區(qū),在進(jìn)行分配之前需要取得分配區(qū)域的鎖。先查看線程私有實(shí)例中是否已經(jīng)存在一個(gè)分配區(qū),如果存在嘗試對(duì)該分配區(qū)加鎖,如果加鎖成功,使用該分配區(qū)分配內(nèi)存,否則該線程搜索分配區(qū)循環(huán)鏈表試圖獲得一個(gè)空閑(沒有加鎖)的分配區(qū)。如果所有的分配區(qū)都已經(jīng)加鎖,那么ptmalloc會(huì)開辟一個(gè)新的分配區(qū),把該分配區(qū)加入到全局分配區(qū)循環(huán)鏈表和線程的私有實(shí)例中并加鎖,然后使用該分配區(qū)進(jìn)行分配操作。開辟出來的新分配區(qū)一定為非主分配區(qū),因?yàn)橹鞣峙鋮^(qū)是從父進(jìn)程那里繼承來的。開辟非主分配區(qū)時(shí)會(huì)調(diào)用mmap()創(chuàng)建一個(gè)sub-heap,并設(shè)置好top chunk;

每一個(gè)進(jìn)程只有一個(gè)主分配區(qū)(main_arena)和若干非主分配區(qū)(non_main_arena),各arena通過一個(gè)循環(huán)鏈表來管理,通過互斥鎖(mutex)使線程對(duì)于該分配區(qū)的訪問互斥。

通過chunk倒數(shù)第三個(gè)標(biāo)志位區(qū)分是否為非主分配區(qū)。

2、將用戶的請(qǐng)求大小轉(zhuǎn)換為實(shí)際需要分配的chunk空間大小

加上chunk頭部,并進(jìn)行字節(jié)對(duì)齊,默認(rèn)8字節(jié)對(duì)齊。

事實(shí)上,由于chunk的空間復(fù)用,例如32位系統(tǒng),實(shí)際的chunk大小=(用戶請(qǐng)求大小 + 8 - 4) align to 8B

3、判斷所需分配chunk的大小是否滿足<=max_fast(32位默認(rèn)為64B),如果是,則轉(zhuǎn)下一步,否則跳到第五步。

4、首先嘗試在fast bin中取一個(gè)所需大小的chunk分配給用戶。如果可以找到,則分配結(jié)束,否則轉(zhuǎn)下一步。

fast bins的分配遵循后進(jìn)先出(LIFO)原則,類似于棧。

fast bins包含10個(gè)bin,大小從16B到88B,相鄰bin相差8B,其中只有前七個(gè)作為空閑chunk鏈?zhǔn)褂谩?/p>

fast bins中的chunk不會(huì)修改最后一個(gè)標(biāo)志位,因此fast bin中的chunk不會(huì)合并。

5、判斷所需大小是否處在small bin中,即判斷chunk_size < 512B是否成立。如果chunk大小處在small bins中,則轉(zhuǎn)下一步,否則轉(zhuǎn)到第6步。

ptmalloc維護(hù)了一個(gè)bin數(shù)組,共有128項(xiàng),其中序號(hào)為2-63的62項(xiàng)為small bin。

small bin中每個(gè)bin中的塊大小相同,相鄰bin相差8B,最小的16B,最大的504B,每個(gè)bin中都是雙向循環(huán)鏈表。

分配時(shí)按照“small-first, best-fit”原則。

6、根據(jù)所需分配的chunk的大小,找到具體所在的某個(gè)small bin,從該bin的尾部摘取一個(gè)恰好滿足大小的chunk。若成功,則分配結(jié)束,否則轉(zhuǎn)下一步。

7、到了這一步,說明需要分配的是一塊大的內(nèi)存,或者small bins中找不到合適的chunk。于是,ptmalloc首先會(huì)遍歷fast bins中的chunk,將相鄰的chunk進(jìn)行合并,并鏈接到unsorted bin中,然后遍歷unsorted bin中的chunk,如果unsorted bin只有一個(gè)chunk,并且這個(gè)chunk在上次分配時(shí)被使用過,并且所需分配的大小屬于small bins,并且chunk的大小大于等于需要分配的大小,這種情況下就直接將該chunk進(jìn)行切割,分配結(jié)束,否則將根據(jù)chunk的空間大小將其放入small bins或是large bins中,遍歷完成后,轉(zhuǎn)入下一步。

ptmalloc中的bins數(shù)組第一個(gè)就是unsorted bin,序號(hào)為1。

雙向鏈表管理空閑chunk,不排序,當(dāng)釋放chunk時(shí),大小大于max_fast的首先鏈入unsorted bin中。

可看作是small bins和large bins的cache。

8、到了這一步,說明需要分配的是一塊大的內(nèi)存,或者small bins和unsorted bin中都找不到合適的chunk,并且fast bins和unsorted bin中所有的chunk都清除干凈了。從large bins按照“small-first, best-fit”原則,找到一個(gè)合適的chunk,從中劃分一塊所需大小的chunk,并將剩下的部分鏈接回bins中。若操作成功,則分配結(jié)束,否則轉(zhuǎn)下一步。

bins數(shù)組序號(hào)為64-126的63個(gè)bin為large bins。

large bins中的chunk鏈大小并不是一個(gè)固定公差的等差數(shù)列,而是分成6組bins,每組bins是一個(gè)固定的等差數(shù)列,每組的bin數(shù)目依次是32、16、8、4、2、1,公差依次是64B、512B、4096B、32768B、262144B等。

9、如果搜索fast bins和bins都沒有找到合適的chunk,那么就需要操作top chunk來進(jìn)行分配了。判斷top chunk大小是否滿足所需chunk的大小,如果是,則從top chunk中分出一塊來,否則轉(zhuǎn)下一步。

chunk中有三種并非按照bins結(jié)構(gòu)存儲(chǔ),分別是top chunk、mmaped chunk、last remainder。

top chunk:對(duì)于非主分配區(qū)會(huì)預(yù)先分配一塊較大的空閑內(nèi)存模擬sub-heap,通過管理sub-heap來響應(yīng)用戶的需求,因?yàn)閮?nèi)存是按地址從高到底進(jìn)行分配的,在空閑區(qū)的最高處,必然存在一塊空閑chunk,叫做top chunk;由于主分配區(qū)是唯一能夠映射到進(jìn)程heap區(qū)域的分配區(qū),它可以通過sbrk()來增大或是收縮進(jìn)程heap的大小,ptmalloc在開始時(shí)會(huì)預(yù)先分配一塊較大的空閑內(nèi)存(heap)。

mmaped chunk: 當(dāng)需要分配的chunk足夠大,而且fast bins和bins都不能滿足要求,甚至top chunk本身也不能滿足要求時(shí),ptmalloc會(huì)使用mmap來直接使用內(nèi)存映射來將頁(yè)映射到進(jìn)程空間。這樣分配的chunk在被free時(shí),將直接解除映射,于是就將內(nèi)存歸還給了操作系統(tǒng)。

last remainder: 不存在于任何bins中,當(dāng)需要分配一個(gè)small chunk時(shí),但在small bins中找不到合適的chunk,如果last remainder chunk的大小大于所需的small chunk大小,last remainder chunk被分裂為兩個(gè),其中一個(gè)chunk返回給用戶,另一個(gè)變成新的last remainder chunk。

10、到了這一步,說明top chunk也不能滿足分配要求,所以,于是就有了兩個(gè)選擇:如果是主分配區(qū),調(diào)用sbrk(),增加top chunk大小;如果是非主分配區(qū),調(diào)用mmap來分配一個(gè)新的sub-heap,增加top chunk大小;或者使用mmap來直接分配。在這里,需要依靠chunk的大小來決定到底使用哪種方法。判斷所需分配的chunk大小是否大于等于mmap分配閾值,如果是的話,則轉(zhuǎn)下一步,調(diào)用mmap分配,否則跳到第12步,增加top chunk的大小。

對(duì)于非主分配區(qū),當(dāng)bins和fast bins都不能滿足分配的需要,ptmalloc會(huì)設(shè)法在top chunk分出一塊內(nèi)存給用戶,如果top chunk本身不夠大,分配程序會(huì)重新分配一個(gè)sub-heap,并將top chunk遷移到新的sub-heap上,新的sub-heap與已有的sub-heap用單鏈表連接起來,然后在新的top chunk上分配。

11、使用mmap系統(tǒng)調(diào)用為程序的內(nèi)存空間映射一塊chunk_size align 4KB大小的空間,然后將內(nèi)存指針返回給用戶。

12、判斷是否為第一次調(diào)用malloc,若是主分配區(qū),則需要進(jìn)行一次初始化工作,分配一塊大小為(chunk_size + 128KB)align 4KB大小的空間作為初始的heap。若已經(jīng)初始化過了,主分配區(qū)則調(diào)用sbrk()增加heap空間,非主分配區(qū)則在top chunk中切出一個(gè)chunk,使之滿足分配需求,并將內(nèi)存指針返回給用戶。

內(nèi)存回收

1、free()函數(shù)同樣首先需要獲取分配區(qū)的鎖,來保證線程安全。

2、判斷傳入的指針是否為0,若為0,則什么都不做,直接return,否則轉(zhuǎn)下一步。

3、判斷所需釋放的chunk是否為mmaped chunk,如果是,則調(diào)用munmap()釋放mmaped chunk,解除內(nèi)存空間映射,該空間不再有效。如果開啟了mmap分配閾值的動(dòng)態(tài)調(diào)整機(jī)制,并且當(dāng)前回收的chunk大小大于mmap分配閾值,將mmap分配閾值設(shè)置為該chunk的大小,將mmap收縮閾值設(shè)定為mmap分配閾值的2倍,釋放完成。否則下一步。

4、判斷chunk的大小和所處的位置,若chunk_size<=max_fast,并且chunk不位于heap頂部,也就是說并不與top chunk相鄰,則轉(zhuǎn)到下一步,否則跳到第6步。(因?yàn)榕ctop chunk相鄰的小chunk也和top chunk進(jìn)行合并,所以這里不僅需要判斷大小,還需要判斷相鄰情況)

5、將chunk放到fast bins中,chunk放入到fast bins中時(shí),并不修改該chunk使用狀態(tài)位P。也不與相鄰的chunk進(jìn)行合并。只是放進(jìn)去,釋放結(jié)束,返回。

6、判斷前一個(gè)chunk是否處在使用中,如果前一個(gè)塊也是空閑塊,則合并,并轉(zhuǎn)下一步。

7、判斷當(dāng)前釋放塊的下一個(gè)塊是否為top chunk,如果是,轉(zhuǎn)第9步,否則轉(zhuǎn)下一步。

8、判斷下一個(gè)chunk是否處在使用中,如果下一個(gè)chunk也是空閑的,則合并,并將合并后的chunk放到unsorted bin中。注意,這里在合并的過程中,要更新chunk的大小,以反映合并后的chunk的大小,并轉(zhuǎn)到10步。

9、如果執(zhí)行到這一步,說明釋放了一個(gè)與top chunk相鄰的chunk。則無(wú)論它有多大,都將它與top chunk合并,并更新top chunk的大小等信息,轉(zhuǎn)下一步。

10、判斷合并后的chunk的大小是否大小FASTBIN_CONSOLIDATION_THRESHOLD(默認(rèn)64KB),如果是的話,則會(huì)觸發(fā)進(jìn)行fast bins的合并操作,fast bins中的chunk將被遍歷,并與相鄰的空間chunk進(jìn)行合并,合并后的chunk會(huì)被放到unsorted bin中。fast bins將變空,操作完成轉(zhuǎn)下一步。

11、判斷top chunk的大小是否大于mmap的收縮閾值(默認(rèn)為128KB),如果是的話,對(duì)于主分配區(qū),則會(huì)試圖歸還top chunk中的一部分給操作系統(tǒng)。但是最先分配的128KB是不會(huì)歸還的,ptmalloc會(huì)一直管理這部分內(nèi)存,用于響應(yīng)用戶的分配請(qǐng)求;如果為非主分配區(qū),會(huì)進(jìn)行sub-heap收縮,將top chunk的一部分返回給操作系統(tǒng),如果top chunk為整個(gè)sub-heap,會(huì)把整個(gè)sub-heap還回給操作系統(tǒng)。做完這一步后,釋放結(jié)束,返回。可以看出,收縮堆的條件是當(dāng)前free的chunk大小加上前后能合并chunk的大小大于64KB,并且要top chunk的大小要達(dá)到mmap收縮閾值,才有可能收縮堆。

轉(zhuǎn)載于:https://www.cnblogs.com/clingyu/p/8620764.html

總結(jié)

以上是生活随笔為你收集整理的ptmalloc内存分配和回收详解(文字版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。