首先蔚携,什么是內存泄露键科?經(jīng)常聽人談起內存泄露剪廉,但要問什么是內存泄露塌计,沒幾個說得清楚赞厕。內存泄露是指無用對象(不再使用的對象)持續(xù)占有內存或無用對象的內存得不到及時釋放唉堪,從而造成的內存空間的浪費稱為內存泄露炸卑。內存泄露有時不嚴重且不易察覺亡蓉,這樣開發(fā)者就不知道存在內存泄露证芭,但有時也會很嚴重瞳浦,會提示你Out of memory(內存泄漏)。
內存泄漏的原因
在Java程序中废士,我們通常使用new為對象分配內存叫潦,而這些內存空間都在堆(Heap)上。
Object object1 = new Object();//obj1
Object object2 = new Object();//obj2
object2 = object1;
//...此時官硝,obj2是可以被清理的
new 出來的對象(new Object())會存在堆內存中矗蕊,而object1這個是堆里對象的引用短蜕,存在于棧上,指向堆中的對象obj1傻咖;但是當堆中的對象沒有引用指向時朋魔,垃圾回收就可以將它的內存收走。
所以object2指向的堆對象是可以被回收(清理)的卿操。因為沒有object1和object2都沒有指向它警检。
內存泄漏就是說堆上的對象得不到及時的回收,導致內存泄漏害淤。
舉個栗子:
public class Simple {
Object object;
public void method1(){
object = new Object();
//...其他代碼
}
}
這里的object實例扇雕,其實我們期望它只作用于method1()方法中,且其他地方不會再用到它窥摄,但是镶奉,當method1()方法執(zhí)行完成后,object對象所分配的內存不會馬上被認為是可以被釋放的對象崭放,只有在Simple類創(chuàng)建的對象被釋放后才會被釋放腮鞍。
這就是一種內存泄露。解決方法就是將object作為method1()方法中的局部變量,當然莹菱,如果一定要這么寫移国,可以改為這樣:
public class Simple {
Object object;
public void method1(){
object = new Object();
//...其他代碼
object = null;
}
}
這樣,之前“new Object()”分配的內存道伟,就可以被GC回收迹缀。
一些容易發(fā)生內存泄露的例子和解決方法
靜態(tài)類/變量引起內存泄露
像HashMap、Vector等的使用最容易出現(xiàn)內存泄露蜜徽,這些靜態(tài)變量的生命周期和應用程序一致祝懂,他們所引用的所有的對象Object也不能被釋放,因為他們也將一直被Vector等引用著拘鞋。
容器使用時的內存泄露
查看集合源碼砚蓬,ArrayList的remove方法
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
各種有close()方法的對象
比如數(shù)據(jù)庫連接(dataSourse.getConnection()),網(wǎng)絡連接(socket)和io連接盆色,以及使用其他框架的時候灰蛙,除非其顯式的調用了其close()方法(或類似方法)將其連接關閉,否則是不會自動被GC回收的隔躲。其實原因依然是長生命周期對象持有短生命周期對象的引用摩梧。
單例模式導致的內存泄露
單例模式,很多時候我們可以把它的生命周期與整個程序的生命周期看做差不多的宣旱,所以是一個長生命周期的對象仅父。如果這個對象持有其他對象的引用,也很容易發(fā)生內存泄露。
內部類和外部模塊的引用
其實原理依然是一樣的笙纤,只是出現(xiàn)的方式不一樣而已耗溜。