Java中,通過(guò)“垃圾回收”機(jī)制雖然能夠?qū)?strong>無(wú)用的對(duì)象從內(nèi)存中刪除,但前提是僅當(dāng)該對(duì)象不再被引用時(shí)才會(huì)被統(tǒng)計(jì)為無(wú)用的。
內(nèi)存泄漏的常見(jiàn)表現(xiàn):
·日志中頻繁出現(xiàn)“OutOfMemoryException”內(nèi)存溢出錯(cuò)誤;
·系統(tǒng)不時(shí)宕機(jī);
·使用分析工具發(fā)現(xiàn)↓
內(nèi)存回收低位點(diǎn)不斷升高(以每次內(nèi)存回收的最低點(diǎn)連成一條直線,那么它是一條上升線);
內(nèi)存回收的頻率也越來(lái)越高,內(nèi)存占用也越來(lái)越高,最終出現(xiàn)"OutOfMemoryException"的系統(tǒng)異常。
內(nèi)存泄漏的原因:
java把內(nèi)存分兩種:一種是棧內(nèi)存,另一種是堆內(nèi)存
1.在函數(shù)中定義的基本類型變量和對(duì)象的引用變量都在函數(shù)的棧內(nèi)存中分配;
2.堆內(nèi)存用來(lái)存放由new創(chuàng)建的對(duì)象和數(shù)組;
在函數(shù)(代碼塊)中定義一個(gè)變量時(shí),java就在棧中為這個(gè)變量分配內(nèi)存空間,當(dāng)超過(guò)變量的作用域后,java會(huì)自動(dòng)釋放掉為該變量所分配的內(nèi)存空間;
在堆中分配的內(nèi)存由java虛擬機(jī)的自動(dòng)垃圾回收器來(lái)管理。
堆的優(yōu)勢(shì)是可以動(dòng)態(tài)分配內(nèi)存大小,生存期也不必事先告訴編譯器,因?yàn)樗窃谶\(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存的。缺點(diǎn)就是要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢;
棧的優(yōu)勢(shì)是存取速度比堆要快,缺點(diǎn)是存在棧中的數(shù)據(jù)大小與生存期必須是確定的無(wú)靈活性。
如何分析:
1.代碼走查和分析,找出程序中潛在的問(wèn)題代碼;
2.使用專門(mén)的內(nèi)存泄漏測(cè)試工具找出內(nèi)存泄漏發(fā)生的位置;
工具的使用↓
·抓取不同時(shí)刻的內(nèi)存快照;
·捕獲堆上的數(shù)據(jù);
·強(qiáng)制執(zhí)行GC,以便觀察受懷疑的類實(shí)例是否會(huì)被作為垃圾收集;
·能顯示出類實(shí)例的引用鏈;
推薦使用Eclipse的插件MAT(Memory Analyzer Tool)來(lái)幫助迅速,準(zhǔn)確地分析內(nèi)存泄漏;
一般說(shuō)來(lái),一個(gè)正常的系統(tǒng)在其運(yùn)行穩(wěn)定后其內(nèi)存的占用量是基本穩(wěn)定的,不應(yīng)該是無(wú)限制的增長(zhǎng)的,同樣,
對(duì)任何一個(gè)類的對(duì)象的使用個(gè)數(shù)也有一個(gè)相對(duì)穩(wěn)定的上限,不應(yīng)該是持續(xù)增長(zhǎng)的。根據(jù)這樣的基本假設(shè),我
們可以持續(xù)地觀察系統(tǒng)運(yùn)行時(shí)使用的內(nèi)存的大小和各實(shí)例的個(gè)數(shù),如果內(nèi)存的大小持續(xù)地增長(zhǎng),則說(shuō)明系統(tǒng)
存在內(nèi)存泄漏,如果某個(gè)類的實(shí)例的個(gè)數(shù)持續(xù)地增長(zhǎng),則說(shuō)明這個(gè)類的實(shí)例可能存在泄漏情況。
分析步驟:
·使用內(nèi)存快照進(jìn)行數(shù)據(jù)收集;
·初步分析,判斷是否存在內(nèi)存泄漏;
·分析定位,找到被泄漏的對(duì)象;
·修正錯(cuò)誤再測(cè)試驗(yàn)證;