什么是內存泄漏,為什么會導致內存溢出?


工作一段時間后,會經常聽到內存溢出,那內存溢出到底是哪里的內存溢出,是什么原因導致的,如何解決,今天就來深入了解一下.

在java中,要了解內存,需要先清楚jvm內存模型,我們常說的java內存實際上就是指Runtime Data Area,分為虛擬機棧、堆、方法區、程序計數器、本地方法棧五個部分.這里不做具體介紹.

1.常見的內存泄露

(1)內存分配未成功,卻使用了它
(2)內存分配成功,但尚未初始化就引用它
(3)內存分配成功且初始化,但操作越過了內存的邊界
(4)忘記釋放內存,造成內存泄漏
(5)釋放了內存卻繼續使用它
以發生的方式來分類:
(1)常發性內存泄漏,發生內存泄漏的代碼會被多次執行到,每次執行都會導致一塊內存泄漏
(2)偶發性內存泄漏
(3)一次性內存泄漏,發送泄漏的代碼只會被執行一次
(4)隱式內存泄漏,程序在運行過程中不停地分配內存,但直到結束時才釋放內存。

2.為什么會導致內存溢出

編寫java程序最為方便的地方就是我們不需要管理內存的分配和釋放,一切由jvm來進行處理,當java對象不再被應用時,等到堆內存不夠用時,jvm會進行垃圾回收,清除這些對象占用的堆內存空間,如果對象一直被應用,jvm無法對其進行回收,創建新的對象時,無法從Heap中獲取足夠的內存分配給對象,這時候就會導致內存溢出。而出現內存泄露的地方,一般是不斷的往容器中存放對象,而容器沒有相應的大小限制或清除機制。容易導致內存溢出。

3.如何發現內存泄漏
可以直接使用VisualVM,已在JDK6.0 update 7 中自帶,能夠監控線程,內存情況,查看方法的CPU時間和內存中的對 象,已被GC的對象,反向查看分配的堆棧.

如果要在服務器上使用Java VisualVM, 比如CentOS。那么就出現 WARNING: environment variable DISPLAY is not set,因為一般服務器都不會裝X server。我們可以在遠程機器上裝一個X server,比如windwos上,那么就可以非常方便的查看服務器運行情況。
如果有大量的FGC就要查詢是否有內存泄漏的問題了,圖中的FGC數量就比較大,並且執行時間較長,這樣就會導致系統的響應時間較長,如果對jvm的內存設置較大,那么執行一次FGC的時間可能會更長。(直接運行linux上的jvisualvm,下載X-Manager,可以將視圖展現在本地機器上。)

從上圖可以發現執行FGC的情況,下午3:10分之前是沒有FGC的,之后出現大量的FGC。

上圖是jvm堆內存的使用情況,下午3:10分之前的內存回收還是比較合理,但是之后大量內存無法回收,最后導致內存越來越少,導致大量的full gc。

4.如何定位內存泄漏

1、查看Visual GC標簽,內容如下,這是輸出first的截圖
            
這是輸出forth的截圖:
通過2張圖對比發現:
老生代一直在gc,當程序繼續運行可以發現老生代gc還在繼續:
增加到了7次,但是老生代的內存並沒有減少。說明存在無法被回收的對象,可能是內存泄漏了。
如何分析是那個對象泄漏了呢?打開抽樣器標簽:點擊后如下圖:
按照程序輸出進行堆dump,當輸出second時,dump一次,當輸出forth時dump一次。
進入最后dump出來的堆標簽,點擊類:
點擊右上角:“與另一個堆存儲對比”。如圖選擇第一次導出的dump內容比較:
比較結果如下:
可以看出在兩次間隔時間內TestMemory對象實例一直在增加並且多了,說明該對象引用的方法可能存在內存泄漏。
如何查看對象引用關系呢?
右鍵選擇類TestMemory,選擇“在實例視圖中顯示”,如下所示:
左側是創建的實例總數,右側上部為該實例的結構,下面為引用說明,從圖中可以看出在類CyclicDependencies里面被引用了,並且被HashMap引用。
如此可以確定泄漏的位置,進而根據實際情況進行分析解決。
 


 

 
        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM