【JVM】java內存洩漏5種情況總結。

Java虛擬機 Java 數據庫 半路出家程序猿 2019-06-28

內存洩漏定義:

一個不再被程序使用的對象或變量還在內存中佔有存儲空間。

由於java的JVM引入了垃圾回收機制,垃圾回收器會自動回收不再使用的對象,瞭解JVM回收機制的都知道JVM是使用引用計數法和可達性分析算法來判斷對象是否是不再使用的對象,本質都是判斷一個對象是否還被引用。那麼對於這種情況下,由於代碼的實現不同就會出現很多種內存洩漏問題(讓JVM誤以為此對象還在引用中,無法回收,造成內存洩漏)。

1、靜態集合類

如HashMap、LinkedList等等。如果這些容器為靜態的,那麼它們的生命週期與程序一致,則容器中的對象在程序結束之前將不能被釋放,從而造成內存洩漏。簡單而言,長生命週期的對象持有短生命週期對象的引用,儘管短生命週期的對象不再使用,但是因為長生命週期對象持有它的引用而導致不能被回收。

2、各種連接

如數據庫連接、網絡連接和IO連接等。在對數據庫進行操作的過程中,首先需要建立與數據庫的連接,當不再使用時,需要調用close方法來釋放與數據庫的連接。只有連接被關閉後,垃圾回收器才會回收對應的對象。否則,如果在訪問數據庫的過程中,對Connection、Statement或ResultSet不顯性地關閉,將會造成大量的對象無法被回收,從而引起內存洩漏。

3、變量不合理的作用域

一般而言,一個變量的定義的作用範圍大於其使用範圍,很有可能會造成內存洩漏。另一方面,如果沒有及時地把對象設置為null,很有可能導致內存洩漏的發生。

 public class UsingRandom {
private String msg;
public void receiveMsg(){
readFromNet();// 從網絡中接受數據保存到msg中
saveDB();// 把msg保存到數據庫中
}
}

如上面這個偽代碼,通過readFromNet方法把接受的消息保存在變量msg中,然後調用saveDB方法把msg的內容保存到數據庫中,此時msg已經就沒用了,由於msg的生命週期與對象的生命週期相同,此時msg還不能回收,因此造成了內存洩漏。

實際上這個msg變量可以放在receiveMsg方法內部,當方法使用完,那麼msg的生命週期也就結束,此時就可以回收了。還有一種方法,在使用完msg後,把msg設置為null,這樣垃圾回收器也會回收msg的內存空間。

4、內部類持有外部類

如果一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由於內部類持有外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存洩露。

5、改變哈希值

當一個對象被存儲進HashSet集合中以後,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,造成內存洩露

(至於第五點,改變哈希值在實際中是什麼情況我不是很明白,望各位評論區大牛指點一二)

相關推薦

推薦中...