1. 程式人生 > >Java JVM:記憶體溢位(棧溢位,堆溢位,持久代溢位以及 nable to create native thread),

Java JVM:記憶體溢位(棧溢位,堆溢位,持久代溢位以及 nable to create native thread),

Hotspot jvm的實現中,將堆記憶體分為了兩部:新生代,老年代。在堆記憶體之外,還有永久代,

其中永久代實現了規範中規定的方法區。

棧溢位:出現此種情況是因為方法執行的時候,棧的深度超過了虛擬機器容許的最大深度所致。

死遞迴:

import java.util.*;    
import java.lang.*;    
public class OOMTest{     
    public void stackOverFlowMethod(){    
        stackOverFlowMethod();    
    }    
    public static void main(String... args){    
        OOMTest oom = new OOMTest();    
        oom.stackOverFlowMethod();    
    }    
}    
Exception in thread "main" java.lang.StackOverflowError    
        at OOMTest.stackOverFlowMethod(OOMTest.java:6)   
根據《java虛擬機器規範》中文版:如果執行緒請求的棧容量超過棧允許的最大容量的話,java虛擬機器將丟擲一個

stackoverflow異常,如果java虛擬機器棧可以動態擴充套件,並且擴充套件的動作已經嘗試過,但是無法申請到足夠的記憶體去完成擴充套件,

或者在新建立現成的時候沒有足夠的記憶體去建立對應的虛擬機器棧,那麼java虛擬機器將丟擲一個outofmemory異常

堆溢位:堆溢位的時候,虛擬機器將會丟擲java.lang.outofmemoryError:java heap space,出現此種情況的時候

需要根據記憶體溢位的時候產生dump檔案來具體分析。出現此種問題的時候可能是記憶體洩漏了,也有可能是記憶體溢位了。

如果記憶體洩漏,我們要找出洩漏的物件是怎麼被gc root引用起來,然後通過引用鏈來具體分析原因

如果出現了記憶體溢位問題,這往往是程式本身需要的記憶體大於了我們給虛擬機器配置的記憶體,這種情況下,我們可以採用調大

-Xmx來解決這種問題

結論:當物件大於新生代剩餘記憶體的時候,將直接放入老年代,當老年代剩餘記憶體還是無法放下的時候,觸發垃圾回收

收集以後還是不能放下就會丟擲記憶體溢位異常了。

持久代溢位

hotspot jvm 通過持久帶實現了java虛擬機器規範中的方法區,而執行時的常量池,就是儲存在方法區中的,

因此持久帶溢位有可能就是執行時常量池溢位,也有可能是方法區中儲存的class物件沒有被及時回收掉或者

class資訊佔用的記憶體超過了我們配置

List list = new ArrayList<>();
        while (true) {
            list.add(UUID.randomUUID().toString().intern());
            System.out.println(list.get(list.size()-1));
        }
字串儲存在堆中的方法區的執行時常量池 執行過程中產生了大量字串 佔用了執行時常量池的大部分空間 最終導致了方法區所在的持久代發生溢位

OutOfMemoryError:unable to create native thread

一般是下面兩種情況導致的:

1.程式建立的執行緒數超過了作業系統的限制。對於Linux系統,我們可以通過ulimit - u 來檢視此限制

2給虛擬機器分配的記憶體過大,導致建立現成的時候的native記憶體太少。

總結:棧記憶體溢位:程式所要求的棧深度過大導致

堆記憶體溢位:分清記憶體洩漏還是記憶體容量不足。洩漏則看物件如何被GC Root引用。不足則設定-Xms,-Xmx引數。

持久代記憶體溢位:Class物件未被釋放,Class物件佔用資訊過多,有過多的Class物件。

無法建立本地執行緒:總容量不變,堆記憶體,非堆記憶體設定過大,會導致能給執行緒的記憶體不足。