關於windows下堆記憶體的申請與釋放

來源:互聯網
上載者:User

著作權,轉載請註明出處,謝謝!
http://blog.csdn.net/walkinginthewind/article/details/7069176

我們都知道,C語言中要動態申請記憶體需要調用malloc函數,釋放動態記憶體需要調用free函數。記憶體的申請與釋放都是在堆(Heap)上進行的。當然,所謂的記憶體,都是虛擬記憶體。

C語言中的malloc和free,在windows中主要是通過HeapAlloc和HeapFree來實現的。
每個進程在初始化的時候,會調用RtlProcessHeap()函數構造進程的HEAP對象,這個對象用來管理進程的堆記憶體。
當我們使用malloc申請一段記憶體時,我們要指定大小,但是使用free釋放的時候,只是指定要釋放的記憶體起始地址即可。
如:
int * p = (int*)malloc(100 * sizeof(int)); // 申請100個int大小的一段記憶體
... // 其他動作
free(p); // 釋放p所指向的記憶體
那麼我們必定會產生疑問,系統是怎麼知道或記錄給定指標所指向的動態記憶體的大小的呢?
windows的實現方案很簡單,就是在每一段動態記憶體的上部儲存該段記憶體的大小等相關資訊,這也就說明了,當我們使用堆記憶體時,會有額外的系統開銷,windows中是通過如下一個結構體來儲存相關資訊的:
(WRK中的定義,在XP和win7下測試符合,win2000源碼中的定義與此不同)

typedef struct _RTL_HEAP_ENTRY {    SIZE_T Size; // 指示該段記憶體的大小    USHORT Flags;    USHORT AllocatorBackTraceIndex;    union {        struct {            SIZE_T Settable;            ULONG Tag;        } s1;   // All other heap entries        struct {            SIZE_T CommittedSize;            PVOID FirstBlock;        } s2;   // RTL_SEGMENT    } u;} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;

因為free釋放記憶體的時候要依賴於該結構體中的資訊,所以對於不是malloc返回的地址或已被釋放過的地址,該結構的內容一般是不正確的,這也就是free會出錯的原因。
如:
int * p = (int*)malloc(100 * sizeof(int)); // 申請100個int大小的一段記憶體
... // 其他動作
free(p); // 釋放p所指向的記憶體
free(p); // 再次釋放已釋放的記憶體,會出錯,因為RTL_HEAP_ENTRY已經不再有效。
所以當我們釋放指標所指的動態記憶體後,我們最好將指標賦值為NULL,因為free一個值為NULL的地址,不會有任何錯誤。
再如:
int * p = (int*)malloc(100 * sizeof(int)); // 申請100個int大小的一段記憶體
... // 其他動作
//比如我們想釋放部分記憶體
int * q = p + 20;
free(q); // 釋放q所指向的記憶體,會出錯,因為地址q所對應的RTL_HEAP_ENTRY結構體資訊是無效的
所以free只能釋放malloc返回的有效地址。
下面通過一個程式驗證一下:

#include<stdio.h>#include<windows.h>typedef struct _RTL_HEAP_ENTRY {    SIZE_T Size;    USHORT Flags;    USHORT AllocatorBackTraceIndex;    union {        struct {            SIZE_T Settable;            ULONG Tag;        } s1;        struct {            SIZE_T CommittedSize;            PVOID FirstBlock;        } s2;    } u;} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;int main(){PRTL_HEAP_ENTRY pHeapEntry;int *p;for(int i = 0; i < 1000; i++){p=(int*)malloc(i);pHeapEntry=(PRTL_HEAP_ENTRY(p)-1);printf("i: %d, size: %d\n", i, pHeapEntry->Size);free(p);}return 0;}

輸出結果是:
i: 0, size: 0
i: 1, size: 1
i: 2, size: 2
...
i: 999, size: 999

總結:本文根據windows源碼簡單的分析了windows對C庫函數free的實現中對記憶體大小資訊的記錄方法。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.