2014-03-03 23 views
4

我得到了一些託管進程的大量內存轉儲,我試圖從堆中獲取大量統計信息 - 以及能夠呈現交互式視圖 - 相當深的對象圖。想象一下與!do <address>相似的東西與SOS設置在WinDbg中,在那裏你可以不斷點擊屬性並查看它們的值,只是在一個非常友好的用戶界面中比較許多對象。如何使用ClrMD正確處理非原始ClrInstanceField值?

我發現Microsoft.Diagnostics.Runtime(ClrMD)是特別適合這項任務,但我有一個困難時期陣列領域的工作和我有點困惑對象字段,我有更好的工作。


陣列: 如果我的目標和地址的陣列直接關閉堆和使用ClrType.GetArrayLengthClrType.GetArrayElementValue事情做工精細,但一旦我通過另一個對象的字段挖,我不當然ClrInstanceField.ElementTypeClrElementType.SZArray(我還沒有遇到Array在我的對象圖中挖掘,但我也想處理它),我從ClrInstanceField.GetValue得到什麼值。

編輯:我只是決定使用ClrTypeSystem.UInt64取消引用數組字段(使用parent address + offset of the array field來計算,其中陣列的指針存儲在地址),那麼我可以與它的工作方式相同,如果我從EnumerateObjects獲得它。我現在遇到了一些不支持ArrayComponentType屬性的陣列。我還沒有用Structs數組進行測試,所以我也想知道它是否是C樣式的嵌入式結構分配,就像int[]或者它是堆中結構的指針數組。 Guid[]是我遇到從ArrayComponentType獲取問題的類型之一。

對象固定(邏輯錯誤) 隨着 ClrInstanceField擁有的 ClrElementType.Object我得到更好的結果 Type,但仍需要更多一點。首先,在撥打 GetFieldValue後,我得到了一個 ulong地址(?),我可以使用 ClrInstanceField.Type.Fields來對付,所以我可以看到嵌套對象的字段名稱和值。也就是說,我必須考慮多態性,所以我嘗試在同一地址上使用 ClrHeap.GetObjectType,並且它返回NULL或者完全不正確。這個地址在我的第一個用例中起作用似乎很奇怪,但不是第二個。

字符串固定(找到解決方法) 因爲我真正的項目已經使用DbgEng W/SOS,我有不同的方法可以輕鬆地獲得通過地址字符串的值,但它似乎很奇怪,試圖使用 ClrInstanceField.GetFieldValue成功返回一個字符串,但結果完全不準確(一堆奇怪的字符)。也許我做錯了?


編輯:我已經提取,現在在LINQPad從我原來的代碼運行的抽象。在這裏發佈會有點長,但全部都是here in a gist。從所有的複製/粘貼/重構中來看,它仍然有點混亂,我會在進一步清理它之後,在解決這些問題後,在CodePlex或GitHub上發佈最終源代碼。

代碼庫相當大,特定於某個項目,但如果絕對必要,我可能能夠提取出樣本集。也就是說,所有對ClrMD對象的訪問都非常簡單。我從SOS命令中獲得初始地址,如 !dumpheap -stat(對根對象工作正常),然後使用 ClrHeap.GetTypeByNameClrHeap.GetObjectType。之後,它完全依靠 ClrType.FieldsClrInstanceField成員 TypeElementTypeGetFieldValue

作爲額外的獎勵,我沒有找到一個browser friendly版本提供的NuGet包的XML文檔,雖然它是相同的文檔的IntelliSense提供。

+0

我已經在ClrMD之上創建了一個擴展庫,與LINQPad很好地整合,如果您感興趣,請檢查下列內容: https://github.com/JeffCyr/ClrMD.Extensions –

回答

3

這將是很難非常精確地回答,沒有看到你的代碼是什麼樣子,但基本上,它是這樣的:

你需要爲了知道的第一件事是能夠調用GetFieldAddress/GetFieldValue如果您擁有的對象地址是常規指針或內部指針。也就是說,如果它直接指向堆上的對象,或者直接指向實際對象內的內部結構(思考實際對象內的字符串與結構字段)。

如果你從GetFieldAddress/GetFieldValue中得到錯誤的值,通常意味着你沒有指定你有一個內部指針(或者你認爲你沒有)。

第二部分是理解這些值的含義。

如果field.IsPrimitive()是正確的:GetFieldValue()將讓你的實際原始值(即一個Int32,字節,或其他)

如果field.IsValueClass()爲真,則GetFieldAddress()會給你一個指向結構的內部指針。因此,您在該地址上使用的任何GetFieldAddress/Value()函數都需要告訴它它是一個內部指針!

如果field.ElementType是一個ClrElementType.String,那麼我似乎記得你需要調用GetFieldValue會得到你實際的字符串內容(需要檢查,但這應該是它)。否則,您有一個對象引用,在這種情況下,GetFieldValue()會爲您提供一個指向新引用對象的常規指針。

這是否有意義?

+0

它非常合理,雖然我認爲我遇到的一些困難是基於我的代碼中的抽象,不知道它是否是內部的;對於某些場景,只需使用Address和Offset就可以輕鬆地考慮,但現在我正在清理我的代碼,我可能會重新使用GetFieldValue。實際上,我已經提取了很多我的代碼,幾乎在LINQPad中獨立運行(與SZArrays掙扎,因爲某些原因,它們不報告它們的ArrayComponentType)。 – TheXenocide

+0

至於字符串,GetFieldValue肯定會返回奇怪的值,但我評論了一種解決方法,我發現它獲取字符串長度,然後使用ReadMemory填充Unicode數據的byte [],這很容易處理。一旦我的獨立程序正確運行,我會更新該帖子並可能要求提供更多反饋?謝謝。 – TheXenocide

+0

我已經更新了問題,該問題現在還包含指向代碼的鏈接。 – TheXenocide