目錄
背景:StackOverflowError(譯爲:堆棧溢出錯誤)當然平時我們稱之爲內存溢出。在回顧LinkedList集合源碼時偶然遇到了該錯誤,由此興趣大發,吟詩作樂(寫博作樂)一發。
先祝各位媽媽母親節快樂,回想上一次母親節,彷彿就在昨天~
一、遇見StackOverflowError的準備
StackOverflowError,在偶然的一次Node節點的相互追加中心動。心動過程來圖
代碼如下
public class StackOverflowErrorDemo {
private static class Node<E> {
/** 當前元素值 (HZ)*/
E item;
/** 當前元素的上一個元素 (HZ)*/
Node<E> next;
/** 當前元素的下一個元素 (HZ)*/
Node<E> prev;
/** 單參構造 @param element 當前元素的值 (HZ)*/
Node(E element) {
this.item = element;
}
}
public static void main(String[] args) {
Node<String> node1 = new Node<>("節點一");
Node<String> node2 = new Node<>("節點二");
node1.next = node2;
node2.prev = node1;
}
}
通過DeBug調試,能看到走到最後一行時,出現了內存溢出異常, 原因爲當執行完node2.prev = node1時,無限循環的添加鏈路就開始了,node2不斷增加變大導致異常。
二、StackOverflowError的心動歷程
那麼執行邏輯是怎麼樣的呢?PS:下圖中綠色區域代碼JVM內存大小。舉例子。當前實際情景遠不止這麼大。
第一步執行時,往內存中存放了一個值“第一關”,此時JVM內存佔據四分之一。
第二步執行時,往內存中存放了新的值“第二關”,此時JVM內存佔據四分之二。
第三步執行時,node1追加了Next等於node2,那麼node1就會擴大一倍。此時JVM佔據四分之三。
第四步執行時,node2也追加了prev等於node1,那麼node2也會擴大一倍、此時JVM佔據慢。
重點:理論上上面四步是走完了所有的過程沒有問題,但是實際上程序的引用依賴鏈不允許它這樣走完,因爲node1與node2是循環依賴鏈,那麼程序底層需要將這個依賴鏈不斷的延續下去。故由此衍生第五步
第五步:在第四步追加了node1的node2之後,node1又需要追加node2作爲下一個的引用依賴,故在JVM內存中,node1繼續追加node2,此時JVM內存已經超過原有值,故拋出異常。當然如果JVM內存夠大,會一直不斷的擴大下去,直到內存溢出,拋出異常爲止。
綜上,JVM內存就可比做是一個容器瓶子,當容器被數據塞滿時,即拋出了內存溢出異常。
故若再次面對內存溢出類似的問題產生時,舉一個生動形象的栗子即可。