教訓:malloc之前確認malloc的長度是否爲0
導致問題:segment fault段錯誤的問題,這種問題很難尋找,所以要避免malloc(0),如果出現類似問題可以二分法加打印定位問題點。
問題分析:
初始化在堆上malloc了一塊區域,但是malloc()的size爲0,這塊地址被用來存了很多數據,數據依然可以使用,但是存的數據會將其他地址踩掉,就會在用其他地址的時候存在segment fault段錯誤問題
關於malloc(0)
在標準的malloc實現中,並不檢查輸入值的大小,而是將輸入值做對齊操作後直接從堆上分配空間。
不論輸入值的大小爲多少,在malloc的內部最小的內存分配大小是一個定值(一般是8B),因爲malloc需要用這部分空間來維護堆上的內存塊鏈表。所以當用戶申請一塊0B的空間時,malloc實際分配的空間是8B,如果用戶申請的空間是X,則malloc實際分配的空間是(對齊(X)+8)。這也是爲什麼malloc分配的空間千萬不能越界使用的原因:堆的內部鏈表結構將被破壞。
對於new和delete malloc和free這樣的內存分配與釋放函數:到底delete和free是怎麼知道要釋放掉多少內存的呢?
其實在new和malloc內存分配成功時,系統除了返回一個指向這塊內存的指針外,還會獲得一塊用於記錄此處分配的內存大小的內存塊
在內存管理中,內存被分爲兩部分:棧和堆。
棧有自己的機器指令,是一個先進後出的數據結構。
malloc分配的內存是堆內存,由於堆沒有自己的機器指令,所以要有系統自己編寫算法來管理這片內存,通常的做法是用鏈表,在每片被分配的內存前加個表頭,裏面存儲了被分配內存的起始地址和大小,你的malloc返回的就是表頭裏的起始指針,這個地址是由一系列的算法得來了,通常不會爲0,一旦分配成功,就返回一個有效的指針,對於分配0空間來說,算法已經算出可用內存的起始地址,但是你佔用0空間,所以對那個指針操作就是錯誤的,操作系統一般不知道其終止地址,因爲有佔用大小就可以推出終止地址,還有就是即使分配0空間也要釋放它,其實是釋放的鏈表結點。
sample
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* temp = NULL;
temp = malloc(0);
printf("the address of temp = %p\n", temp);
}
輸出結果:
the address of temp = 0x685010
說明malloc(0)是會返回malloc的地址,只是malloc的地址長度爲0