侯捷 - C++ Startup 揭密:C++ 程序的生前和死后 (二)
2.內存分配
先膨脹大小決定要多大內存,然后去拿內存,拿完后函數(shù)返回,然后設置區(qū)塊串接。
2.1 計算分配的大小并設定值
malloc_crt:
調試模式——使用一般的malloc分配內存
非調試模式——malloc_dbg分配內存并登記一些信息(所在的FILE,LINE)。
因此,任何一個C++程序第一次分配的內存大小都是 IOINFO_ARRAY_ELTS * sizeof(ioinfo) = 256 。它用來作為_cdecl_ioinit()函數(shù),即IO初始化。
在調試模式下,要加上上下文等相關信息,加完的長度要登記在cookie之中(圖中的00000131,在之前的130的基礎上需要1個bit登記狀態(tài)),最后要進行字節(jié)對齊。
100h(轉化位10進制:256)+ 24h(36) + 8h(8) ?= 12ch -> 130h (16的邊界)。上圖字節(jié)補齊的4個字節(jié)沒有畫出。
我們來看heap_alloc_dbg函數(shù):
heap的客戶(需要被分配內存的地方)可能是CRT本身 ,可能應用程序。在要完內存后,若小于1K,該區(qū)塊將被膨脹(上文提出),膨脹完后會去SBH挖取一塊內存(后文將介紹),然后區(qū)塊將被串接起來(如下圖Debug Heap 雙向鏈表)。
heap_alloc_bae:內存門檻檢查,小于1K將從SBH拿取內存,大于將從操作系統(tǒng)的內存池去拿(下圖不小心備注錯了)
2.2 去SBH拿取內存
在32位的電腦沒有64位變量可以用,bitvGroup被分為了Hi和Lo兩部分,BITVEC是unsigned int型,為32位。所以,共有[32]組,每組64bits。
作為heap的管理者,怎么去管heap的區(qū)塊呢?我們都是挖一大塊內存,有需要的時候切出去,當我回收的時候它們的大小是相同的:比如我給ABC3個人,它們需要不同大小的內存,它們還給我的時候,如果還的大小是一樣的,我就想辦法把它管理在一起,而不要散落在原始的物理的那一部分,例如我們可以使用特殊的設計將它串在一起(如上圖,將內存串接起來)。
回到上圖,該設計準備了64條雙向鏈表,負責管理64種大小。當回收的時候,有相同的大小,我們就把他鏈在特定的某個鏈表上(邏輯上是連續(xù)的,物理上卻不是)。
1 MegaByte,拿出其中的1/32即32K(因為其不希望一次管理太多內存),在將32K切為8塊,每塊為4K。
將page放大來看:
當切出130bytes出去立馬就變成了131bytes了,我們之前說過,因為它的這個設計需要1個bytes表示它的狀態(tài)是給出去了還是在SBH手中。?
0xffffffff表示為-1(上下個占8個byte),用來防止鏈表合并。4096-8*2=4088。前面講過希望設計大小是16的倍數(shù),最靠近16邊界的是4080,因此8bytes保留。
?總結:
首先,我們有16個header,每一個header管理的事情是1M里面的32K切成8塊,這8塊是由64條鏈表來管理。
一開始是最后一條鏈表負責把page8鏈接起來(130=304/16=19,從0開始排列,19-1=18。理論應該是#18 List進行供應,但因為現(xiàn)在這些鏈表都是空的,只有最后一個鏈表是有掛載page,所以第18號鏈表是空的,最后發(fā)現(xiàn)最后一個鏈表的page起著作用,所以在page中把130bytes切出去了)
在page中把130bytes切割出來。130bytest、是所有程序都會面臨,_ioinit()需要的內存大小就是130bytes,于是剩下ec0bytes 。這就是首次內存分配。
接下來對page1繼續(xù)切割(只有當page1 內存切割完成后,才會去切割page2的內存),當切割至第15次,開始釋放。
鏈表的各自任務是以16在變化的,所以由#35 鏈表進行回收。#35 鏈表的指針將指向240bytes的地址。
這樣回收由什么好處呢?下一次客戶需要240bytes大小空間時,#35 鏈表將直接給它。
當?shù)?6次分配內存時,將分配b0大小。操作系統(tǒng)將從之前釋放的240bytes中的空間重新切割。240-b0=190,剩下的190將重新分配給#24 List維護管理。所以,內存切割分配是個動態(tài)的過程,不斷調整所屬的鏈表。
區(qū)塊的合并
合并后的空間也將重新分配給鏈表進行管理。
內存塊將回到最初始的狀態(tài),理論上它可以在合并,但是應為我們前面說過,特意放上separate分隔的東西(0xffffffff),所以它不能繼續(xù)合并。
?
————————————————
版權聲明:本文為CSDN博主「Jeff_」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_40539125/article/details/101083127
總結
以上是生活随笔為你收集整理的侯捷 - C++ Startup 揭密:C++ 程序的生前和死后 (二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工作59:常见报错
- 下一篇: 前端学习(2758):view基本使用