2010-02-25 25 views
5

內存泄漏是,當應用程序中有未使用的內存並且GC可以收集它時,通常會發生如果某些應用程序中存在不必要的強引用的對象,並且GC將能夠找到路徑(直接和間接)它可以釋放這個對象,但是這對於引用類型來說都是真實的,這意味着在堆內存分配中。在.NET中,堆棧中是否也可能發生內存泄漏?

但對於堆而且據我所知GC將不負責清理堆棧,機器會自動清潔時,函數將返回。

所以我的問題是,是否有內存泄漏會在堆棧也發生任何的機會?如果是,那麼在什麼情況下,什麼是最好的做法,以避免這種泄漏。

回答

2

如果你正在編寫保持到未子的遞歸調用需要大量的數據堆棧的局部引用遞歸函數,那麼這是一個類型的內存泄露的,但它是非常不尋常的這是一個問題實踐。

更一般地,如果您有類似

Main() { 
    var s = ReadInAGiganticString(); // say 10 Megs long 
    Server(s.Substring(0,5));   // but I only care about first 5 chars 
} 
Server(s) { 
    while(true) { ... }    // but 10M is on stack forever 
} 

那麼這是一種堆棧空間泄漏的,但同樣的,它是不可能在實踐中。解決方法是簡單的:

Main() { 
    var s = ReadInAGiganticString(); 
    var t = s.Substring(0,5); 
    s = null;       // the fix 
    Server(t); 
} 
Server(s) { 
    while(true) { ... } 
} 

在一般情況下,如果你有在堆棧上一個巨大的變量調用,將持續「很長一段時間」和變量不再使用之前的權利,你可以空出來以確保在進入「長期」通話之前可以通話。

(這可能是一種優化可以爲您基於可達性分析做到這一點。)

注意的是,以上的答案是植根在堆棧上堆分配的對象引用。另一方面,如果你有堆棧分配的內存(例如一個巨大的struct或stackalloc thingie),那麼修復就不那麼容易了,但在實踐中這更爲罕見(誰創造了巨大的結構?)。

+1

只有對字符串的引用位於堆棧上,字符串本身駐留在堆上。 – 2010-02-25 08:55:37

0

堆棧分配的變量在塊結束後被銷燬。所以內存泄漏不可能發生。牀的做法是創建至於你說的GC不清理堆棧是隻用在一個給定的塊塊

0

以外的變量。然而,堆棧使用的空間在展開期間被回收。所以隨着堆棧被彈出,堆棧指針被移回「後退」,因此空間可以被重用。

暗戰的堆棧空間將提高StackOverflowException。這通常是由於無限遞歸的編程錯誤。

0

不知道太多關於.NET的內部我會說,如果你有一個堆棧泄漏,你將有一個崩潰的程序,因爲函數/方法返回地址也被存儲在堆棧中(最有可能的) 。

如果你的籌碼被莫名其妙地對準你會比內存泄漏遠遠更大的問題。

通常方法參數和返回值都存儲在堆棧上(如果沒有優化通過cpu寄存器發送)。

0

不,只要您使用安全代碼,堆棧變量就不會發生內存泄漏。

1

如果您未能正確釋放非託管資源,則可能發生內存泄漏。所以我擔心,如果你發送一個託管對象給一個方法,並且這個對象包裝一個非託管資源,並且它無法正確釋放這個非託管資源,將會出現內存泄漏。該堆棧將釋放託管引用,但非託管資源將保持活動狀態。