雖然當咱們用完對象後,java有垃圾回收機制進行回收,可是並無那麼的智能,對於某些被引用的對象,就算咱們已經不在使用它了,可是java的回收機制是不會回收他們的,人們稱之爲「內存泄漏」。java
不少時候內存泄漏都是「人們無心識的內存引用」形成的,舉個簡單的例子:數組
List<String> list = new ArrayList<>(); String str = "testString"; list.add(str); str = null;
看似上面的str被回收了,可是,事實上建立str時所開闢的內存空間是不會被回收的,由於list依然持有對str的引用這就是一個典型的「無心識的內存引用」。爲了防止這些「無心識的內存引用」,咱們應該瞭解對象相互引用的時候是存在怎樣的依賴關係的。spa
下面咱們在看看一個簡單的棧實現例子:code
public class Stack{ private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack(){ elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e){ //判斷是否放的下,放不下進行擴展 ensureCapacity(); elements[size++] = e; } private void ensureCapacity(){ if(elements.length == size){ elements = Arrays.copyOf(elements,2*size+1); } } public Object pop(){ if(size == 0){ throw new EmptyStackException(); } Object result = elements[--size]; return result; } }
看似這段程序沒有明顯的錯誤,也能運行,可是這裏面存在一個內存泄漏問題,若是棧先增加了,而後在收縮,那麼棧中彈出的對象將不被當作垃圾回收,即便使用棧的程序不在引用這些對象了,它們也不會被回收,由於棧內部維護着對這些對象的過時引用,所謂的過時引用是指永遠不在會被解除的引用,這裏就是凡在elements數組的活動部分以外的任何引用都是過時的。對象
對於上述這些修復的方法仍是比較簡單的,一旦對象是過時引用,只須要清空這些引用便可,對應上述例子中的Stack而已,只要一個單元被彈出棧,那就是過時引用,只須要在pop方法的return result上面加上elements[size] = null;便可。blog
固然,咱們不要由於懼怕內存泄漏而在全部的地方都手動回收內存,這樣會致使咱們的代碼凌亂臃腫,不利於管理,咱們應該把目標集中在那些長聲明週期的變量中,哪些是長生命週期的變量呢,最明顯的一個就是static修飾的變量,咱們應該把目光放在這些變量上。 生命週期