2008-09-08 20 views
4

這是一個有點假設和粗略簡化,但...如何登錄mallocs

假設一個程序,將調用第三方寫的函數。這些政黨可以被認爲是非敵對的,但不能被認爲是「有能力的」。每個函數都會接受一些參數,產生副作用並返回一個值。他們沒有跑步時沒有狀態。

目標是確保它們不會通過記錄所有malloc(等等)而導致內存泄漏,然後在函數退出後釋放所有內容。

這可能嗎?這是否實用?

附:對我而言,重要的一點是確保沒有分配方式能夠持續消除內存泄漏,而不會對我無用。

回答

4

不指定操作系統或環境中,這個答案假設Linux上,glibc的,和C

您可以設置__malloc_hook,__free_hook和__realloc_hook指向將通過malloc被調用的函數() ,realloc()和free()。有一個顯示原型的__malloc_hook聯機幫助頁。您可以在這些鉤子中添加軌道分配,然後返回讓glibc處理內存分配/解除分配。

聽起來好像你想在第三方函數返回時釋放任何現場分配。有辦法讓gcc使用-finstrument-functions在每個函數入口和出口處自動插入調用,但是我認爲這對你正在嘗試做的事來說是不合適的。在調用其中一個第三方函數之後,你可以讓自己的代碼在你的內存跟蹤庫中調用一個函數嗎?然後您可以檢查是否有第三方功能尚未釋放的任何分配。

1

難道你不能只是強迫他們把所有的內存分配到堆棧上嗎?通過這種方式,在函數退出後可以釋放它。

2

比嘗試登錄malloc更好的解決方案可能是在調用它們時對沙箱進行沙箱功能 - 讓他們訪問固定的內存段,然後在該函數完成運行時釋放該段。

無限制,無能的內存使用情況可能與惡意代碼一樣具有破壞性。

3

您可以在單獨的進程中運行第三方功能,並在完成使用庫時關閉進程。

4

首先,您必須提供malloc()free()和朋友的入口點。由於此代碼已編譯(對嗎?),因此您不能依賴#define進行重定向。

然後,您可以通過明顯的方式實現這些功能,並通過將這些例程鏈接到這些模塊來記錄它們來自某個模塊。

最快的方法涉及根本不記錄。如果他們使用的內存數量是有限的,爲什麼不預先分配他們需要的所有「堆」,並編寫一個分配器?然後,當完成時,釋放整個「堆」,你就完成了!如果它更復雜,你可以將這個想法擴展到多個堆。

如果你確實需要「登錄」而不是自己創建分配器,這裏有一些想法。一,使用帶指針和內部鏈接的散列表。另一種方法是在每個塊前分配額外的空間,並將自己的結構包含在你的「日誌表」中,然後保留一個自由列表的日誌表條目(作爲一個堆棧,以便獲得一個免費的表)或者把一個免費的回來是O(1))。這需要更多的記憶,但應該快。

它是否實用?我認爲,只要擊中速度是可以接受的。

0

由於您擔心內存泄漏並且在討論malloc/free,我假設您使用的是C語言。我還根據您的問題假設您無權訪問第三方的源代碼圖書館。

我能想到的唯一的事情就是在調用之後檢查你的應用的內存消耗,然後記錄錯誤消息,如果它們不同並且說服第三方供應商修復你發現的任何泄漏。

1

在過去我寫了一個C語言的軟件庫,它有一個內存管理子系統,它包含記錄分配和釋放的能力,並且手動匹配每個分配和空閒。這在嘗試查找內存泄漏時有用,但使用起來很困難且耗時。日誌的數量是壓倒性的,並且需要大量的時間來理解日誌。這就是說,如果你的第三方庫有大量的分配,那麼通過日誌記錄來追蹤這個數據可能不切實際。如果您在Windows環境中運行,我會建議使用Purify [1]或BoundsChecker [2]等應該能夠檢測第三方庫中的泄漏的工具。對工具的投資應該及時爲自己節省。

[1]:http://www-01.ibm.com/software/awdtools/purify/淨化

[2]:http://www.compuware.com/products/devpartner/visualc.htm的BoundsChecker

0

如果你有閒錢,那麼可以考慮使用Purify來跟蹤問題。它可以創造奇蹟,並且不需要源代碼或重新編譯。還有其他的調試malloc庫更便宜。電籬笆是我記得的一個名字。也就是說,Denton Gentry提到的調試鉤子也很有趣。

0

如果你對Purify來說太窮了,試試Valgrind。它比6年前好很多,比Purify更容易深入。

+0

是啊 - valgrind的作品也很好。感謝您的提醒。 – 2008-10-21 04:14:29

0

Microsoft Windows提供(使用SUA,如果您需要POSIX),很可能是當今任何裝運操作系統的最先進堆+(已知使用堆的其他api)基礎架構。

__malloc()調試鉤子和關聯的CRT調試接口對於有測試源代碼的情況很好,但是它們通常會錯過標準庫或其他鏈接代碼的分配。這是預期的,因爲它們是Visual Studio堆調試基礎結構。

gflags是一個非常全面和詳細的調試功能,已包含在Windows中多年。具有用於源和二進制的高級功能僅用於使用情況(因爲它是OS堆調試基礎結構)。

它可以在所有堆修改入口點(如果需要的話)串行地記錄所有堆用戶的完整堆棧跟蹤(在後處理操作中重新標記符號信息)。而且,它可以修改具有可能對齊數據分配的分佈式情況的堆,使得由VM系統提供的頁面保護被最優地分配(即,在頁面末尾分配請求的堆塊,因此在溢出時也會檢測到單字節溢出。

umdh是一種工具,可以幫助評估各個檢查點的狀態,但數據在執行目標過程中不斷積累,而不是傳統上下文中的簡單檢查點調試停止。另外,警告,最後我檢查了至少,每個請求存儲堆棧信息的循環緩衝區的總大小有點小(64k條目(條目+堆棧)),因此您可能需要快速轉儲堆用戶。還有其他方式可以訪問這些數據,但umdh非常簡單。

備註有2種模式;

  1. MODE 1,UMDH {-p:進程ID | -pn:ProcessName} [-f:文件名] [-g]
  2. MODE 2,UMDH [-d] {File1中} [文件2 ] [-f:文件名]

    我不知道什麼瘋狂抓住了開發人員選擇在-p:foo參數說明符和參數的裸排序之間切換,但它可能會有點混亂。

調試SDK可與許多其他工具,memsnap是一個工具,這顯然側重於記憶leask等,但我沒有用它,你milage可能會有所不同。

對於UI模式執行不帶參數的gflags,+ arg和/ args是不同的「模式」也有用。