我一次性malloc十個單位節點的內存空間出來賦值給L, 現在我想一次性刪除從第3個到第6個節點,我是這麼做的:
1.將第六個節點的next指針指向NULL
2.將L指針指向第三個單位空間的地址,再free(L)。
等到把代碼寫完之後,才發現其中的問題:這裡我的free(L)用的對嗎?
編譯運行了一下才發現了問題所在。
為了清楚地看到這個錯誤,將這個問題簡化出來,請看下面的代碼:
[cpp]
#include <stdio.h>
#include <malloc.h>
int main()
{
char *p = (char*)malloc(sizeof(char) * 10);
char *q = p;
int i = 0;
for (; i < 10; i++)
printf("%08X\n", q + i);
q = q + 2;
free(q);
return 0;
}
編譯執行之後結果如下:
0863E008
0863E009
0863E00A
0863E00B
0863E00C
0863E00D
0863E00E
0863E00F
0863E010
0863E011
*** glibc detected *** ./free: free(): invalid pointer: 0x0863e00a ***
======= Backtrace: =========
/lib/libc.so.6[0x4481d9f2]
./free[0x8048487]
/lib/libc.so.6(__libc_start_main+0xf3)[0x447be6b3]
./free[0x8048391]
======= Memory map: ========
......
已放棄(吐核)
在linux下面可以看到free這句代碼是不能被運行的。
那麼為什麼執行會出錯呢?
這裡首先要談談malloc和free這兩個函數的用法了。
首先我們要知道的一個原則就是:malloc 和free是成對使用的。
你可能會奇怪為什麼malloc指定了內存分配的長度,而free的時候沒有指定釋放的內存長度。
因為是成對使用的,所以滿足下面兩個原則:
1.我們free的指針必須是malloc出來返回給你的指針。
2. 所以,free的長度是你malloc要求分配的長度。
看到這裡可能有人會問:你是怎麼得出這兩個結論的呢?
好吧,現在我們就來深究一下,free函數在操作系統內存中究竟是怎麼實現的。
但是畢竟自己實力有限,還是菜鳥一枚,如果讓我閱讀free 和malloc 的源代碼,肯定是不現實的,貌似有1500多行。。。。
自己摘除了一點基本信息:
malloc/free 是操作系統提供的接口
不同的系統可能使用不同的庫
接口形式相同,但是實現方式可能不同
這主要取決於操作系統內存管理模式
VC使用的CRT,而GCC使用的是libc
裡面有兩段比較經典的話。雖然正確性還有待考證。摘錄如下:
1.
內核通過一個紅黑樹來記錄了空閒的內存,malloc就是從樹中查找一塊大小適合的內存並把地址給你,然後把這個節點從樹中摘除,避免被別人分配到產生沖突。這個內存現在歸你一個人用了。
free函數是把你的這個內存重新放回到紅黑樹中,讓別人可以申請到這個內存。從邏輯上來說,你現在不能在使用這個內存了,因為它已經不屬於你。但是系統的實現上目前沒有做到,所以你還是能訪問這個地址。
另外,系統也不會幫你覆蓋內存中的數據,因為做這一個操作浪費時間,沒有必要。
打一個簡單的比方。你租了一套房子,後來租期到了,房子回到房東手裡,或者又轉租給別人。但是你拿著原來的鑰匙還是能進入那套房子,雖然這個是不合法的。
2.
應該確切講是不變的。內存管理多數是通過一個MBC鏈表實現的,及你實際分配的內存空間為:(nSize + 3) / 4 * 4 + sizeof(MBC)的大小,在malloc之後,系統程序實際返回的是分配的MBC地址+sizeof(MBC),釋放內存時,free所做的第一個動作是ptr - sizeof(MBC)得到實際的MBC塊,在這個MBC塊中包含了該內存的大小,內存MBC鏈的指針等信息;所以,如果你使用了超出實際分配內存大小的空間,會造成整個MBC鏈的混亂,最直接表現是程序在free時在另一個不相關的地方出現了異常;所以您可以看出來,在執行了free之後,該塊內存並沒有改變,即使該塊內存相鄰內存為空,而發生了內存塊的合並,您剛才使用的內存空間也沒有發生改變(你看到的),改變的是MBC鏈表;
詳細的內存管理程序您可以參考一些庫,如dlmalloc,這個庫除了使用了MBC鏈外,還是用了沙箱機制;事實上早期DOS的內存管理程序也是使用的MBC鏈;
3.
1)我注意到之上的回復多數是基於系統端的,(如紅黑樹,我在Understand Linux kernal中還真沒有聽說過紅黑樹,最後居然在國內網站找到了 ---- 不知道是不是只是國內學術名詞,是內核的內存管理);系統內存分配涉及屬性、內存頁面以及是否有MCU;但是注意一點malloc和free並不是直接使用系統內存管理程序,在多數Linux程序中malloc和free一般是通過標准庫,及我說過的DL內存管理程序實現的;因此,內核的內存管理和我們在應用層面的內存管理(如malloc/free)不要混為一談;
2)DL的內存管理從效能上要比直接使用系統的內存管理效能要高,如經過我們實測:在隨機大小、隨機順序申請釋放 ---- 目的在制造最差情況,DL內存管理程序是直接使用系統的3~3.9倍,考慮使用realloc,DL內存管理程序是系統的10~43.35倍;所以,實際情況下,我們並不是直接使用系統內存管理 ---- 只是我們並不知道。