Glib 內部使用記憶體切片分配器(GSlice)與緩存機制,標準 Valgrind 檢測會誤報大量「possibly lost」內存塊。必須禁用 Glib 優化分配器,強制使用系統 malloc/free,才能獲得準確洩漏報告。
G_SLICE=always-malloc G_DEBUG=gc-friendly \
valgrind --tool=memcheck \
--leak-check=full \
--leak-resolution=high \
--num-callers=20 \
--show-reachable=yes \
--log-file=valgrind.log \
./your_app
G_SLICE=always-malloc:禁用 GSlice 切片分配器,所有分配直接走 malloc,讓 Valgrind 精確追蹤。G_DEBUG=gc-friendly:讓 Glib 在程式結束時主動釋放所有內部緩存、全局變量,減少「still reachable」干擾。--leak-check=full:輸出詳細洩漏堆疊追蹤(含源碼行號)。--leak-resolution=high:高解析度匹配洩漏堆疊,區分相似調用路徑。--num-callers=20:堆疊追蹤深度 20 層,覆蓋深層調用鏈。--show-reachable=yes:顯示「still reachable」內存(全局/靜態指針指向),輔助判斷是否為刻意保留。--log-file=:將龐大輸出導向文件,便於事後分析。#!/bin/bash
# valgrind_test.sh
killall ../bin/test 2>/dev/null
export G_SLICE=always-malloc
export G_DEBUG=gc-friendly
valgrind --tool=memcheck \
--leak-check=full \
--leak-resolution=high \
--num-callers=20 \
--show-reachable=yes \
--log-file=valgrind_test.log \
../bin/test --verbose --no-daemon --timed-exit
==31312== LEAK SUMMARY:
==31312== definitely lost: 0 bytes in 0 blocks
==31312== indirectly lost: 0 bytes in 0 blocks
==31312== possibly lost: 689,572,150 bytes in 576,549 blocks
==31312== still reachable: 10,452 bytes in 9 blocks
==31312== suppressed: 0 bytes in 0 blocks
g_hash_table、g_slist、g_string、g_array)未釋放。需結合堆疊定位業務代碼創建這些對象的位置。典型洩漏堆疊模式:
==31312== 4,856,400 bytes in 20,235 blocks are possibly lost in loss record 35 of 53
==31312== at 0x4C26458: memalign (vg_replace_malloc.c:727)
==31312== by 0x31A2055F47: ??? (in /lib64/libglib-2.0.so.0.2200.5)
==31312== by 0x31A2056801: g_slice_alloc (in /lib64/libglib-2.0.so.0.2200.5)
==31312== by 0x31A2057D7D: g_slist_prepend (in /lib64/libglib-2.0.so.0.2200.5)
==31312== by 0x40438A: mr_new (gsmmr.c:274) <-- 業務代碼入口
==31312== by 0x4048DC: read_gsmmr_file (gsmmr.c:414)
==31312== by 0x40507B: read_mr_file (mrread.c:56)
==31312== by 0x404BEE: test_read_gsmmr_file (test_mrread.h:26)
==31312== by 0x404EE3: main (main.c:28)
mr_new → read_gsmmr_file → main。g_slist_prepend / g_hash_table_new_full / g_string_sized_new 等 Glib 容器操作未對應釋放(g_slist_free、g_hash_table_destroy、g_string_free)。g_hash_table_new_full 指定 key_destroy/value_destroy 回調,確保 g_hash_table_destroy 時遞歸釋放值內存。g_free、g_list_free、g_array_free)。g_slist_free(list) 僅釋放節點,不釋放節點數據;需先遍歷 g_free(data) 或使用 g_slist_free_full(list, g_free)。cleanup_all() 釋放所有全局容器。--track-origins=yes:追蹤未初始化值來源,定位 Conditional jump or move depends on uninitialised value(s) 錯誤根因。VG_(VALGRIND_MALLOCLIKE_BLOCK) / VALGRIND_FREELIKE_BLOCK:在業務代碼嵌入 Valgrind 客戶端請求,標記自定義分配器內存塊,提升精度。G_SLICE=always-malloc vs 默認模式,差異即為 Glib 內部緩存佔用量。「possibly lost」在 Glib 程式中常態化,關鍵在於業務代碼層面是否正確配對釋放。建立「創建即規劃銷毀」編碼習慣,配合 CI 集成 Valgrind 自動化檢測,才能從根本上杜絕記憶體洩漏。