2009-10-28 56 views
3

我試圖追查當我強調我的C#代碼並在低內存條件下運行時發生的崩潰。但是,在某些情況下,我的程序只會崩潰並退出,而不是發生OutOfMemoryException。這通常是由於溢出緩衝區或堆棧溢出(或損壞)導致的內存損壞引起的。在C#中檢查堆完整性和堆棧大小

那麼,有沒有辦法檢查堆的完整性,還是有辦法檢查一個線程剩下多少堆棧?

爲了速度的原因,我使用了很多不安全的代碼,所以很可能我的代碼在某處破壞了內存。不幸的是,在腐敗發生後,崩潰發生在隨機間隔。我知道C#會在檢測到緩衝區溢出時關閉應用程序,但有沒有辦法強制它執行檢查?

謝謝。

+0

它沒有顯示任何異常而退出嗎?您是否嘗試過在發行版和調試模式下進行編譯和測試?你想要的是一個對話框,告訴你如何「未處理的異常」或「分段錯誤」或類似的東西,給你一個線索。 – csl 2009-10-28 15:29:41

+0

是的,它只是沒有任何例外而退出。我已經在發佈和調試模式下進行了測試。沒有不同。您可以通過使用stackalloc從堆棧中請求更多內存然後實際上可用,從而獲得類似的崩潰。也就是說,你不會遇到堆棧溢出異常,程序就會退出。 請注意,這種崩潰只發生在內存不足的情況下。所以也許這畢竟不是腐敗。也許像JIT這樣的內存耗盡並導致退出。 – AZDean 2009-10-28 16:57:46

+0

另外請注意,我必須關閉虛擬內存的自動調整來強制內存不足的情況。換句話說,我真的強迫它耗盡內存。 我在閱讀有關「受限制的執行區域」,但我不明白這對我有何幫助。這個問題使我的程序在代碼中不可預知的地方崩潰,到處都是。我無法讓我的整個計劃成爲CER。 – AZDean 2009-10-28 16:58:42

回答

3

可以通過使用Constrained Execution Regions處理這些情況:

約束的執行區域(CER)是用於創作可靠託管代碼的機構的一部分。 CER定義了公共語言運行庫(CLR)受到限制的區域,該區域不會拋出帶外的異常,這些異常會阻止區域中的代碼完整執行。在該區域內,用戶代碼被限制執行的代碼可能會導致帶外異常。 PrepareConstrainedRegions方法必須立即在try塊之前,並將catchfinallyfault塊標記爲約束執行區域。一旦標記爲受限區域,代碼只能調用具有強可靠性合同的其他代碼,代碼不應分配或虛擬調用未準備或不可靠的方法,除非代碼準備處理失敗。 CLR延遲線程中止在CER中執行的代碼。

當然,CERs是非常嚴格的。你不能在他們身上做很多事情。它們專爲關鍵的小部分代碼而設計。

1

當操作系統別無選擇,只能抹去過程時,有一定的條件。爲了在進程中引發堆棧溢出或段錯誤等異常,內核必須在錯誤堆棧上寫入EXCEPTION_RECORD,然後再將控制權交還給進程。如果沒有空間來寫這個記錄,那麼這個過程就會消失,沒有任何事情可以阻止它。我知道這種情況可能發生的兩種情況是,如果您在EXCEPTION_STACK_OVERFLOW之後繼續增長堆棧或者不能提交保留的堆棧頁面,這兩種情況都非常罕見。

你最好的辦法是糾正腐敗。嘗試在gflags PageHeap保護下運行。如果您知道發生異常的地方,請嘗試在調試器下的緩衝區中設置寫入時斷點斷點。或者嘗試通過寫入模式(例如可以是字符串)或搜索內存以查找引用返回到緩衝區來驗證塗鴉師驗屍。

2

雖然試圖追查我的問題,我發現這些文章是非常有益的:

Investigating Memory Issues

When memory is running low…

IGCHost Interface

Getting the most out of .NET by taking control

的最後一篇文章說以下:

如果內存不能分配給 異常對象,運行時將 終止而不給予例外 處理程序來執行,這 很少會期望的行爲的機會。 [所以,]而不是簡單地拒絕 分配任何進一步存儲器,溫和 和更有效的技術是 允許一個小的存儲器增加,使 異常對象可以成功 創建和OutOfMemory例外 可以擺好拋出由 託管代碼處理。

我相信這是我需要做的,以避免我的問題。由於我的應用程序內存密集,我不能讓它將內存垃圾分頁到分頁文件,因爲這非常非常慢。我需要我的應用程序來限制自己的物理內存,以保持性能可以接受。但是當它耗盡內存時,我需要引發內存不足的異常。我不能讓應用程序崩潰!

因此,我將實施該文章中提到的技術,看看是否可以解決我的問題。不幸的是,這有點複雜,所以嘗試一下並不是一件快事。