很多人可能在想這么一個(gè)問題:Java有垃圾回收機(jī)制,那么還存在內(nèi)存泄露嗎?答案是肯定的,所謂的垃圾回收GC會(huì)自動(dòng)管理內(nèi)存的回收,而不需要程序員每次都手動(dòng)釋放內(nèi)存,但是如果存在大量的臨時(shí)對象在不需要使用時(shí)并沒有取消對它們的引用,就會(huì)吞噬掉大量的內(nèi)存,很快就會(huì)造成內(nèi)存溢出。
一、Java的垃圾回收機(jī)制
Java中的對象是在堆中分配,對象的創(chuàng)建有2中方式:new或者反射。對象的回收是通過垃圾收集器,JVM的垃圾收集器簡化了程序員的工作,但是卻加重了JVM的工作,這是Java程序運(yùn)行稍慢的原因之一,因?yàn)镚C為了能正確釋放對象,必須監(jiān)控每一個(gè)對象的運(yùn)行狀態(tài),包括對象的申請、引用、被引用、賦值等,GC都要進(jìn)行監(jiān)控,監(jiān)控對象的狀態(tài)是為了更加準(zhǔn)確、及時(shí)地釋放對象,而釋放對象的根本原則就是該對象不再被引用。
三、Java中的內(nèi)存泄露
內(nèi)存泄露的對象有以下兩個(gè)特點(diǎn):
① 這些對象是可達(dá)的,即在有向圖中存在通路可以與其相連。
② 這些對象是無用的,即程序以后都不會(huì)再使用這些對象。
public class Stack {
private final static int MAX_ATTRIBUTE = 10;
private Object[] arr;
private int index = 0;
public void push(Object obj) {
if (index > 9)
throw new IllegalArgumentException();
arr[index] = obj;
index++;
}
public Stack() {
arr = new Object[MAX_ATTRIBUTE];
}
public Object pop() {
if (index < 0)
throw new IllegalArgumentException();
return arr[--index];
}
}
這個(gè)程序那里發(fā)生了內(nèi)存泄露呢?如果一個(gè)棧先增長然后收縮,那么從棧中彈出來的對象將不會(huì)被當(dāng)做垃圾回收,即使使用棧的程序不再引用這些對象,它們也不會(huì)被回收,因?yàn)闂?nèi)部維護(hù)這對這些對象的過期引用。
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; //Eliminate obsolete reference
return result;
}
解決辦法:只要一個(gè)元素被彈出棧,那么就將它的引用置為空,GC就會(huì)回收。即一旦數(shù)組元素變成了非活動(dòng)部分的一部分,就手工清空這些數(shù)組元素。
不要被類似的問題困擾
當(dāng)程序員第一次被類似這樣的問題困擾的時(shí)候,他們往往會(huì)過分小心;對于每一個(gè)對象引用,一旦不再使用它,就把它清空,這是沒有必要的,這樣反而會(huì)把代碼弄的混亂。清空對象的引用應(yīng)該是一種例外(因?yàn)樗鼉H在一些特殊的情況下才需要進(jìn)行),而不是一種規(guī)范行為。消除過期引用最好的辦法是讓包含該引用的變量結(jié)束其生命周期。如果是在最緊湊的作用域范圍內(nèi)定義每一個(gè)變量,這種情況就會(huì)自然而然地發(fā)生。
一般而言,只要類是自己管理內(nèi)存,就應(yīng)該警惕內(nèi)存泄漏問題。一旦元素被釋放掉,則該元素中包含的任何對象引用都應(yīng)該被清空。
四、常見的內(nèi)存泄露
① 緩存。一旦你把對象引用放到緩存中,它就很容易被遺忘掉,從而使得它不再有用之后很長一段時(shí)間內(nèi)仍然留在緩存中。
② 在Java程序中,我們經(jīng)常要和監(jiān)聽器打交道,通常調(diào)用諸如addXXXListener()等方法來增加監(jiān)聽器,但往往忘記刪除這些監(jiān)聽器,從而增加了內(nèi)存泄漏的機(jī)會(huì)。
③ 使用連接池時(shí),除了要顯式地關(guān)閉連接,還必須顯式地關(guān)閉Resultset和Statement對象。否則會(huì)造成大量的這些對象無法釋放,從而引起內(nèi)存泄露。
④ 盡量少用靜態(tài)變量,因?yàn)殪o態(tài)變量存放在永久代,永久代基本不參與垃圾回收