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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从源码角度剖析VC6下的内存分配与切割的运作

發布時間:2023/12/1 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从源码角度剖析VC6下的内存分配与切割的运作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 前言
  • 1、heap初始化
  • 2、第一次分配內存,計算真正區塊大小
  • 3、new_region管理中心
  • 4、__sbh_alloc_new_group()切割第一次分配好的內存
  • 5、開始切割內存

前言

malloc與free帶來的內存管理是應付小區塊的,即SBH(small block heap),這點也可以從源代碼中看出:
VC6下會做門檻檢測

if(size <= __sbh_threshold) { pvReturn = __sbh_alloc_block(size); return pvReturn; } ... return HeapAlloc(_crtheap,0,size)

VC10下不會做門檻檢測,它總是會調用系統提供的HeapAlloc。這是因為操作系統提供的函數也有類似的功能了。
當然還需要注意,我們分析的步驟是按照函數調用的次序來的:(從下往上的函數調用次序如下)

1、heap初始化

首先向操作系統要一大塊內存(如4096),稱為_crtheap.
然后使用HeapAlloc從_crtheap中獲取16個HEADER大小的內存,并獲取內存指針。
每個HEADER長這樣:

圖1 圖2

2、第一次分配內存,計算真正區塊大小

在debug模式下,通過調用malloc_dbg,分配得到32個8字節的內存,即100h.
然后調整大小,擴充一個如下的結構:nDataSize記錄真正大小。gap用戶調試器檢查保護nsize內存。注意gap一共上下兩個,但是結構體里面只定義了上面的那個。

圖1 圖2
我們將這整個內存的大小叫做blockSize: 然后調用heap_alloc_dbg函數,進行結構體與nSize的整合


通過調用_heap_alloc_base來獲取每個blockSize內存的頭指針。
然后通過頭尾指針將所有分配出來的block串接起來,變為一個鏈表:

頭指針為_pFirstBlock;
尾指針為_pLastBlock;
_heap_alloc_base具體內容
之前在通過heap_alloc_dbg中調用_heap_alloc_base來獲取每個blockSize內存的頭指針。
現在來看看它具體步驟:
1、首先將擴充完的大小與__sbh_threshold進行比較,所過是小區塊就用shb服務,否則由操作系統服務。
小區塊的定義是:這塊內存大小+cookie大小 < 1024個字節

if(size <= __sbh_threshold) { pvReturn = __sbh_alloc_block(size); return pvReturn; } ... return HeapAlloc(_crtheap,0,size)

接下來看__sbh_alloc_block具體細節:
對擴充完的區塊再次進行擴充,加上8個字節(上下cookie)并且進行roundup操作(變為16的整數倍)

以上圖為例,最終得到的結果是0x130,但是在cookie中寫入的卻是131。這是因為由于是16的倍數,所以最后一位一定是0。最后一位0/1表示是在SBH手上還是已經分配出去了。

3、new_region管理中心

之前在第一步heap初始化的時候分配了16個HEADER,每個HEADER現在用來管理1MB的內存。每個HEADER有兩根指針:一根指向虛擬地址空間,一根指向管理中心。
管理中心被稱為new_region。
region設計如下:
它含有:
1個整數
64個char
32個Hi和32個Lo并起來,構成32組,每組64個bit。(用來管理哪些區塊有或者沒有)
32個group,每個group由64根雙向鏈表組成。

圖1 圖2
程序將用這一塊region(大概16KB左右)來控制1MB的虛擬內存空間。 程序通過調用__sbh_alloc_new_region()、__sbh_alloc_new_group()函數開始內存管理。

4、__sbh_alloc_new_group()切割第一次分配好的內存

已知擁有32個group,對應了1MB的虛擬內存空間,平均下來每個group管理32KB內存。
每32KB的內存還要再分割,分成8page(注意這里的內存都是連續的),每page4KB,然后用指針把8個page串起來。串起來之后將它們掛到group的最后一條鏈表。這便是SBH現在所作的事情。
下面紅色部分便是group與32KB內存的具體銜接圖。

0xfff…實際上就是-1,作用:
將來回收內存的時候需要合并內存,合并的過程中需要用-1作為阻隔器,即只能合并-1與-1之間的內存。
上-1下面有3格,第一格記錄的是兩個-1之間的內存,一開始大小為4080,后兩格作為指針將page從前到后串聯起來。
每個page大小4096字節,去掉兩個-1,剩下4088個字節。由于每個紅色區塊要保證大小是16倍數。所以需要將4088再分割出去8個字節(也就是保留)。
每個4K都這樣處理,形成如下的圖:

5、開始切割內存

先前講到了每個group中有64根雙向鏈表,平均分配下來:
第一條鏈表管理16個字節的內存
第二條鏈表管理32個字節的內存

最后一條管理1024個字節的內存(實際上大于1k的內存全都歸最后一條管理)

現在開始想象開始切割page1的內存,當page1內存小于1k的時候就不應該由最后一條鏈表來管,應該要計算,然后將指定鏈表拉過來。現在來看具體的切割:
在之前的步驟中我們以及知道我們需要的內存是多大了:130h(100h+debugHeader+cookie+roundup)
所以,現在還剩下ec0h的內存。切割完后,系統將紅色的地址:007d0ed0,傳出去。
客戶程序拿到該指針,便認為擁有了這一塊內存。
由上可知,切割其實只是cookie的調整 + 指針的傳送。
注意紅色指針還需要調整(扣除debugHeader),調整到右邊的結構塊的綠色部分,該部分才是使用者(ioinit)真正拿到的地址。

總結

以上是生活随笔為你收集整理的从源码角度剖析VC6下的内存分配与切割的运作的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。