動態儲存管理_free崩潰
阿新 • • 發佈:2018-12-01
一、 生存期
從變數值的存在時間(生存期)來觀察。有的變數在程式執行的整個過程都是存在的,而有的變數則是在呼叫其所在函式才臨時分配儲存單元,而在函式呼叫結束後該儲存單元就馬上釋放了,變數就不存在了。
1.1 靜態儲存方式
是指在程式執行期間由系統分配固定的儲存空間的方式。
1.2 動態儲存方式
是指在程式執行期間根據需要進行動態的分配儲存空間的方式。下面我們討論一下free因何崩潰。
二、 free崩潰
void __cdecl free(
_Pre_maybenull_ _Post_invalid_ void* _Block
);
本宣告來自VS2017, 從宣告我們可以看到,free函式的引數只有1個——無型別的指標。這就帶來一個問題:釋放申請的空間,不借助其他引數,作業系統如何知曉用完待釋放的空間的大小呢?既然函式傳參時不能體現,肯定就在別處解決了。需要留心邊界標誌法
2.1 上越界
#include<malloc.h> #include<stdio.h> #include<assert.h> int main() { int *p = (int*)malloc(10); //申請10byte的空間 assert(NULL != p); p++; free(p); //p向上偏移進行解引用取出塊的大小時發生錯誤 段錯誤 return 0; }
2.2 下越界
#include<malloc.h>
#include<stdio.h>
#include<assert.h>
int main()
{
int *p = (int*)malloc(10); //申請10byte的空間
assert(NULL != p);
for (int i = 0; i < 10 + 1; ++i) //故意設定成陣列訪問越界
{
p[i] = 1;
}
free(p); //下越界
return 0;
}
2.3 重複釋放同一塊空間
#include<malloc.h> #include<stdio.h> #include<assert.h> int main() { int *p = (int*)malloc(10); //申請10byte的空間 assert(NULL != p); free(p); free(p); //第二次,屬於重複free return 0; }
三、 realloc
對於動態記憶體開闢這個行為:我們不會去討論生存期或者地址高低,前者不必要是因為動態開闢的記憶體會一直存在 until 主動free或者程式結束;後者是因虛擬地址空間和段頁機制的存在,先申請的記憶體不一定位於低地址,後申請的記憶體不一定位於高地址。
3.1 情況1
#include<malloc.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
int main()
{
int *p = (int*)malloc(10); //申請10byte的空間
assert(NULL != p);
printf("%x\n", p);
int *q = (int*)malloc(10); //防止在p的尾部追加空間
p = (int*)realloc(p, 200); //原有空間釋放,申請200byte的空間
printf("%x\n", p);
free(p);
return 0;
}
3.2 情況2
#include<malloc.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
int main()
{
int *p = (int*)malloc(10); //申請10byte的空間
assert(NULL != p);
printf("%x\n", p);
int *q = (int*)malloc(10); //防止在p尾部新增空間
p = (int*)realloc(p, 6); //原有空間釋放,申請6byte的空間
p[8] = 100;
printf("%x\n", p);
free(p); //如果是新申請的空間,越界時將崩潰,但是最後驗證了並沒有崩潰
return 0;
}
3.3 小結
void* __cdecl realloc(
_Pre_maybenull_ _Post_invalid_ void* _Block,
_In_ _CRT_GUARDOVERFLOW size_t _Size
);
宣告來自VS2017,_Size指的是新空間的大小。策略是的:1 如果再分配的空間 ≤ 原有的空間,realloc實際上是一個空殼函式,什麼也不做,申請下來的空間還是原來的空間,但是這一過程對使用者透明。這一點在3.2節得到了驗證——並沒有執行記憶體緊縮,以空間換區時間,回收記憶體是一件很麻煩的事情;2 如果再分配的空間>原有空間,可能會在原有空間後面追加一塊空間;也可能是先釋放原有空間,然後新申請一塊空間。後者是更為常見的,因為無法確保原有空間後是否還有足夠的空間。