Memory Leakage 除錯技巧 – 自己的記憶體管理函式庫

動態記憶體分配是程式設計時,幾乎都會用到的功能。隨著程式越寫越大,動態分配的記憶體散佈在各處,這時開始就容易發生 memory leakage 的問題 – allocate 之後沒有 free。在 User mode, 就造成系統緩慢,記憶體耗盡,process 被中止。 在 Kernel mode 就會影響到整個系統的穩定性。

當然,有 memory leakage 的問題,最好是能找到根本原因,是哪邊沒有 free 掉。但有更多的狀況是要花很久的時間才能複制出來,或程式是別人寫的,或是 Open Source 套件,難以快速找到其根本問題。

自己的記憶體管理函式庫

與其找到問題發生的原因,更簡單的方式是使用自己的記憶體分配函式庫 (Memory Allocator)。這邊說的「自己」,也不是真的自己寫的。就是找到第三方提供的函式庫。這裡提到的是 ARM mbedTLS 裡的一個 buffer management 的功能。ARM mbedTLS 一直有持續在改版,目前的檔案結構已經有點不一樣,我所使用的是 2.5.1,可以在 WoLTE_TLSClient 這個專案裡找到。mbedTLS 的說明則在這裡可以找到。

mbedTLS memory allocator 提供的功能,可以指定一塊記憶體供 allocate/free,而不分配超過這塊記憶體的範圍。這塊記憶體可以是 stack 或 heap 都可以。透過這個 library,有幾個好處:

  1. 分配的記憶體空間上限就會被限制住,而不會無限的成長。
  2. 如果發生 memory leakage 現象,可以把某個程式元件重置就好了,而不需全部重置。
  3. 透過 usage 觀察,可以知道一個軟體元件在 init/deinit 後,是否有造成 memory leakage。

應用場景

在 Linux Mosquitto MQTT Clients 與 公用Broker 驗証 這篇文章裡就是使用到 mbedTLS 來進行 TLS 驗証。而 mbedTLS 在這版本裡,本身就會造成每次連線約 5kb 的 memory leakage。我們可以在每次連線後觀察 max memory usage 而得知這個現象。解決方法(迴避比較洽當…)也很簡單,就是把 memory allocator reinit,並且把 TLS object reinit 即可。

測試程式碼

mbedTLS memory allocator 的簡化 library 已附在文末。這邊我們說明一下裡面的例子。

 

行5: 利用一塊 stack 記憶體來當做 memory allocator 使用的空間。由於本程式是測試性質,直接使用 stack。一般是使用 heap 的記憶體,才不會 return 後就被回收。

行9: memory allocator 初始化,初始化內部的資料結構。

行12: 此 memory allocator 是利用 mbedtls_calloc() 來分配記憶體。其 prototype 與 calloc() 一樣,方便使用。所有分配的記憶體都會被限制在mbedtls_memory_buffer_alloc_init() 所指定的 buffer 內。 若要清除目前的分配紀錄,再呼叫一次 mbedtls_memory_buffer_alloc_init() 即可。

行16: mbedtls_memory_buffer_alloc_status() 可以印出目前分配的狀況,與分配的峰值。再下個表格內,會說明其內容。

行23: 回收記憶體,與free() 的 prototype一樣。這邊我們把回收的程式碼 comment 掉,是為了我們觀察每次分配後的狀況。一般使用,應該要在適當的時機將其回收。

行26: 釋放 memory allocator buffer。其實其內部沒做什麼事,只是把內部資料結構清成0。

 

分配結果

Current use: 分配了幾個 block,共多少 bytes

max: 分配的峰值,最多分配了幾個blocks / bytes。後面有寫個 total  則是將其 header 算進來,這邊可以看出來。每個 block 會有 64 bytes 的 overhead。

alloc/free :  分配與回收的次數。

結語

Memory allocator library 只是個工具,利用這個工具,可以提供一些資訊來幫助使用者瞭解記憶體是否有被回收。解決 memory leakage 的過程,當然不可能一步到位。當確認有 memory leakage 問題後,還是得要一步步的縮小範圍,直到找出沒正確釋放的地方。

附件

ARM Mbedtls Memory Allocator

Leave a Reply(Name請以user_開頭,否則會被判定會垃圾息)

請輸入答案 − 4 = 4