關於malloc的一些想法

2022-08-01 16:39:10 字數 1402 閱讀 7924

之前一段時間翻閱過一些記憶體分配的資料,這次終於能將其整理記錄下來了。

c標準庫里有兩個耳熟能詳的函式,用於對堆空間的記憶體進行分配和釋放,它們分別是:

malloc。負責分配乙個指定大小的一塊記憶體給呼叫的程式,函式返回乙個指向這塊記憶體的指標。

free。對函式引數指向的記憶體塊進行釋放操作。

需要說明的是,不管是malloc還是free,這些函式都是c標準庫提供給我們的,而不是作業系統的api。對於堆上的記憶體管理,作業系統(linux)提供以下兩個介面:

sbrk。用於擴張和收縮堆,本質上就是移動指向堆頂的指標。把指標向高位址移動就是在擴張堆、向低位址移動就是在收縮堆。

mmap、munmap。用於記憶體對映和取消記憶體對映,對於大塊的記憶體申請,直接呼叫mmap申請乙個記憶體段更加高效。

顯然,malloc的實現是基於作業系統提供的api的,也就是上面提到的那兩個syscall。而且,一般考慮到會頻繁的進行記憶體分配,我們往往希望能儘量減少syscall的次數。於是,通常的策略是如下。

一般地,實現會在內部維持了乙個空閒記憶體塊的鍊錶,當我們通過malloc申請一塊記憶體,我們先在這個煉表裡進行搜尋,如果找到符合大小的記憶體塊,就將這個記憶體塊返回給呼叫程式。否則,當在空閒鍊錶中搜尋不到滿足要求的記憶體塊,說明當前堆的大小不夠用了,呼叫syscall以擴張堆的大小,並重新搜尋記憶體塊。當通過free釋放記憶體的時候,則將記憶體塊返回給這個空閒鍊錶。空閒鍊錶可能會有一些策略,用來在未來的某乙個時候,通過syscall將這些空閒的記憶體重新歸還給作業系統。

不同的malloc/free的實現,主要是在如何組織這個空閒記憶體塊的鍊錶上有所不同。關於glibc的malloc可以參考這篇文章:glibc記憶體管理。

在清楚malloc內部做了什麼之後,就可以搞明白一些詭異的問題了。比如說,重新引用一塊已經free掉的記憶體,為什麼有時候會報段錯誤,有時候會崩潰,有時候什麼事都沒發生?

首先要說明的是作業系統的記憶體管理是段頁式的,既分段也分頁。而通常乙個程式的記憶體段有:**段、靜態資料全域性資料段、堆、棧等,而程式所能訪問的位址必須是在os已經分配的記憶體段中。如果訪問的位址不在已存在的段內,就會報我們熟悉的段錯誤。當通過free將記憶體釋放時,分配程式有可能為了重新利用這塊記憶體而快取著它,也有可能將這塊記憶體真正的歸還給作業系統。如果記憶體塊被真正的歸還給作業系統,比如free操作導致了堆的收縮,或是在free中呼叫了munmap取消了乙個記憶體對映。這時候如果有乙個指標指向這塊記憶體位址,對它引用就會導致段錯誤。

不過大多數情況下,free掉的記憶體塊不是立即歸還給os,而是被分配程式(malloc)插入到空閒記憶體塊鍊錶中快取起來,等待再次被利用。有的實現(例如glibc的ptmalloc)為了記憶體空間的復用,會在這個記憶體塊裡面記錄下指向鍊錶前後節點的指標等資訊。這時候如果我們對free掉的記憶體塊重新執行寫操作就有可能會改寫這部分資訊,導致這個記憶體塊被寫壞,破壞了空閒鍊錶的結構,因此就有可能引起崩潰。

關於OCR,一些想法

ocr一般分為兩種 1,根據給定的字元特徵集合,提取未知字元的特徵進行匹配識別 典型例子 gocr 2,不知道字元特徵,但給出提取特徵的規則,通過機器學習training來獲取某個字符集的特徵集,對未知字元進行匹配識別。典型例子 tesseract 第一種方法簡單,在某些場合很高效,但比較侷限,字符...

關於tv app的一些想法

以前是做iptv機頂盒的,現在是做網際網路電視機頂盒的,在技術上的區別是不大的。通過這些年與電信,廣電打交道,現在對產品有了一些小想法。那麼在顯示上都是以web為主,用web來顯示epg內容,用osd來顯示狀態。但是隨著android的出現,現在大部分機頂盒或電視劇集廠家,都開始了智慧型之旅。乙個是...

關於敏捷的一些想法

敏捷軟體開發宣言 個體和互動 勝過 過程和工具 可以工作的軟體 勝過 面面俱到的文件 客戶合作 勝過 合同談判 響應變化 勝過遵循計畫 今天看了robert martin的ppp一書的第一部分,敏捷開發 回顧了自己曾經加盟過的幾個公司,經歷過的大大小小的專案,感慨良多。這些公司中不乏奉過程開發為寶典...