2011-08-01 21 views
2

我們正在處理.Net程序中的GC太快。 因爲我們使用具有本地資源的類,並且不調用GC.KeepAlive(),GC在本機訪問結束之前收集對象。結果程序崩潰了。如何使JIT擴展堆棧變量到示波器末端(GC太快)

Does the .NET garbage collector perform predictive analysis of code?

像這樣: 這裏描述我們有完全相同的問題

{ var img = new ImageWithNativePtr(); 
    IntPtr p = img.GetData(); 
    // DANGER! 
    ProcessData(p); 
} 

的觀點是:JIT生成表明,IMG是不是在點時使用的GC信息GetData()運行。如果一個GC線程在正確的時間到來,它收集img和程序崩潰。可以通過附加GC.KeepAlive(img)來解決這個問題。 不幸的是,已經寫了太多的代碼(在太多的地方),很容易糾正這個問題。

因此:有沒有例如一個屬性(即ImageWithNativePtr)使JIT的行爲就像在一個調試版本?在Debug構建中,變量img將保持有效,直到作用域結束(}),而在Release中,它在註釋DANGER時失去有效性。

+0

我相信'GC.KeepAlive'是你唯一的選擇。 –

+0

您的非託管資源是否需要某種處置? –

+1

取決於愚蠢實現的代碼被破壞。 – delnan

回答

2

據我所知,沒有辦法根據方法引用的類型來控制抖動的行爲。您可能可以將方法本身歸類,但這不會填滿您的訂單。這是如此,你應該咬緊牙關,重寫代碼。 GC.KeepAlive是一種選擇。另一種方法是讓GetData返回一個安全的句柄,該句柄將包含對該對象的引用,並且ProcessData接受句柄而不是IntPtr - 無論如何,這是一個很好的練習。然後,GC將保持安全句柄,直到方法返回。如果您的代碼中的大部分代碼都是var而不是IntPtr,那麼您甚至可能在不修改每種方法的情況下離開。

+0

如果一個安全句柄/專用對象不可能是最具表現力的語法(而不是KeepAlive)將使'ImageWithNativePtr'實現'IDisposable'並將代碼包裝在'使用(var img = new ImageWithNativePtr()){...}' –

+0

事實上,這需要更多的代碼更改。順便說一下'ImageWithNativePtr'可以從'SafeHandle'派生。 –

+0

IDisposeable策略當然被認爲是通過 - 但是這需要大量的代碼更改。唯一要堅持的事情仍然是指導的範圍。但是,正如我們所知,GC的工作更快捷。 – Hui

1

您有幾個選項。

  1. (需要工作,更正確的) - 你的ImageWithNativePtr類實現IDisposable因爲它編譯成try { ... } finally { object.Dispose() },這將保留該對象活着爲您提供using秒的更新你的代碼。你可以通過安裝類似CodeRush(即使免費的Xpress支持這個)來緩解這種做法的痛苦 - 它支持創建using塊。
  2. (更簡單,不正確,更復雜的構建) - 使用Post Sharp或Mono.Cecil創建您自己的屬性。通常這個屬性會導致GC.KeepAlive()被插入到這些方法中。

CLR沒有內置此功能。

0

我相信你可以用一個實現IDispose的容器和using語句來模擬你想要的東西。使用語句允許定義範圍,並且您可以在其中放置任何需要在該範圍內活動的任何內容。如果你無法控制ImageWithNativePtr的實現,這可能是一個有用的機制。

處理東西的容器是一個有用的習慣用法。特別是當你真的應該處理某些事情時......這可能是一個圖像的情況。

using(var keepAliveContainer = new KeepAliveContainer()) 
{ 
    var img = new ImageWithNativePtr(); 
    keepAliveContainer.Add(img); 
    IntPtr p = img.GetData(); 
    ProcessData(p); 
    // anything added to the container is still referenced here. 
} 
+0

好主意 - 雖然我會把圖像作爲構造參數。 – Hui