我最近在WinForms應用程序中查看了一些.NET「內存泄漏」(即意外的,滯留的GC根源對象)。在加載並關閉一個巨大的報告之後,即使在幾個gen2集合之後,內存使用率也沒有像預期的那樣下降。假設報告控件被一個流浪事件處理程序保持生存,我打開WinDbg以查看發生了什麼.......NET正則表達式「內存泄漏」調查
使用WinDbg,!dumpheap -stat
命令報告字符串實例消耗了大量內存。通過!dumpheap -type System.String
命令進一步細化,我找到了罪魁禍首,在地址爲03be7930的報告中使用了一個90MB的字符串。最後一步是調用!gcroot 03be7930
來查看哪個對象保持活着狀態。
我的期望不正確 - 它不是懸掛在報告控件(和報告字符串)上的未掛鉤事件處理程序,而是它由System.Text.RegularExpressions.RegexInterpreter
實例保留,該實例本身是System.Text.RegularExpressions.CachedCodeEntry
的後代。現在,正則表達式的緩存(有點)是常識,因爲這有助於減少每次使用時重新編譯正則表達式的開銷。但是,這與保持我的字符串活着有關呢?
基於使用Reflector進行分析,事實證明,每當調用Regex方法時,輸入字符串都存儲在RegexInterpreter中。 RegexInterpreter持有這個字符串引用,直到通過隨後的Regex方法調用將一個新的字符串提供給它爲止。我期望通過掛在Regex.Match實例以及其他可能的實例上來實現類似的行爲。該鏈是這樣的:
- Regex.Split,Regex.Match,Regex.Replace等
- Regex.Run
- RegexScanner.Scan(RegexScanner是基類,RegexInterpreter是上述的子類)。
- Regex.Run
違規的正則表達式是僅用於報告,很少使用,因此不太可能被再次使用,以清除現有的報表字符串。即使後來使用了正則表達式,它也可能會處理另一個大的報告。這是一個相對重要的問題,只是普通的感覺很髒。
說了這麼多,我發現了一些關於如何解決這個問題,或者至少解決這個問題的方案。我會讓社區先回應,如果沒有參與者出面,我會在一兩天內填補任何空白。
是否使用在創建正則表達式的'Compiled'選項? – 2010-04-29 16:31:00
沒有,是不是在這種情況下使用的'Compiled'選項。 – 2010-04-30 00:45:03