1. 程式人生 > >聊聊3種記憶體溢位OOM(OutOfMemory)

聊聊3種記憶體溢位OOM(OutOfMemory)

記憶體溢位有3種,我們最熟悉的就是堆記憶體溢位異常,比如我們new一個物件或者陣列,如果超出了JVM的heap記憶體最大限制就會爆出異常 比如:
從這句話我們可以知道,棧記憶體溢位有2種異常一種是:StackOverflowError、另一種是OutOfMemoryError StackOverflowError是指【執行緒】的棧記憶體不足,導致【執行緒】丟擲了StackOverflowError。
執行緒的stack是執行緒獨有的,預設大小通常1M,可以通過-Xss來設定,比如-Xss128k,-Xss越大,則執行緒獲得棧記憶體越大,越難出現棧記憶體溢位。不過從經驗上來講,1M的棧記憶體是足夠的,如果還出現棧記憶體溢位,就只能說明程式有問題,常見的就是線上程內過度的進行函式呼叫,函式呼叫會消耗棧空間,比如拼命的進行遞迴呼叫,這個時候你得考慮在演算法上做優化了。 下面是程式碼演示(僅供參考):


遞迴函式呼叫棧開避了7493開始發現Main執行緒的棧空間不足,所以丟擲了main執行緒的棧空間不足的異常
如果我把-Xss2m那麼可開避的函式呼叫棧會差不多翻一倍

而JVM虛擬機器本質上是作業系統上的一個程序,所以他也擁有自己的系統堆空間和棧空間。 JVM的棧空間被所有執行緒分割成一塊一塊的,每個執行緒只佔用一塊。而JVM的棧空間的最小分配單位由-Xss來決定,沒錯,-Xss有兩個語義, 即定義了每個執行緒的棧大小,也定義了虛擬機器的最小棧記憶體的分配單位。我們甚至可以估算出,虛擬機器可以建立的最大執行緒數,即作業系統可以分配給程序的最大棧空間大小除以-Xss的值,就可以得到最大活躍執行緒數。如果先申請的執行緒沒有棧空間可以分配了就會丟擲 OutOfMemoryError。表示【JVM虛擬機器】的棧空間不足,溢位異常。 下面是演示程式碼(注意,這個實驗可以能會因為JVM申請太多棧記憶體,導致作業系統因為棧空間不足出現假死。我的記憶體16G,所以妥妥的):

程式碼中我設定了-Xss1m 我開啟了N多個執行緒,然後讓所有執行緒等待(持有棧空間,不釋放)。 你會發現很快丟擲了異常。 如果我設定為-Xss128k 你會發現要等很久才會丟擲異常,因為每個執行緒才128K,所以可以分配的執行緒變多了,所以for又多運行了幾次,才沒那麼快宕機。