天天看點

JVM進階

記憶體結構圖

GC作用域

常見的垃圾回收算法:

①引用計數:有對象引用就加1,沒對象引用就減1,到0為止回收;  雙端循環引用特别容易報錯;

應用:微軟COM/ActionScrip3/Python...

缺點:每次對對象指派時均要維護引用計數器,且計數器本身也有一定的消耗;  較難處理循環引用;  ===> JVM的實作一般不采用這種方式。

②複制:用在新生代;幸存者0區和幸存者1區,GC時會進行交換;複制--清空--交換; 優點是沒有産生記憶體碎片(整體複制),缺點是有點浪費空間;

③标記清除:标記---清除,會産生碎片  ;;

JVM進階

④标記整理: 既不浪費空間又不産生碎片但它耗時很長;

    ③④用于老年代比較多

JVM進階

GC Root

記憶體中已經不再被使用到的空間就是垃圾;要進行垃圾回收如何判斷一個對象是否可以被回收?

①引用計數法:

 Java中,引用和對象是有關聯的。如果要操作對象則必須用引用進行;  通過引用計數來判斷一個對象是否可以回收,即給對象添加一個引用計數器,當有一個地方引用它,計數器值加1,當有一個引用實效時,計數器值減1。任何時刻計數器值為0的對象就是不可能再被使用的,那麼這個對象就是可回收對象。

但主流java虛拟機裡都沒采用這種算法,因為它很難解決對象之間互相循環引用的問題。(了解即可)

JVM進階

 枚舉根節點做可達性分析(根搜尋路徑)

為了解決引用計數法的循環引用問題,java使用了可達性分析的方法。

JVM進階

所謂"GC Roots"或者說tracing GC的“根集合” 就是一組必須活躍的引用。

基本思路就是通過一系列名為"GC Roots"的對象作為起始點,從這個被稱為GC Roots的對象開始向下搜尋,如果一個對象到GC Roots沒有任何引用鍊相連時,則說明此對象不可用。也即給定一個集合的引用作為根出發,通過引用關系周遊對象圖,能被周遊到的(可到達)對象就被判定為存活;沒有被周遊到的就自然被判定為死亡。

可達性分析/ 根搜尋路徑:從GC Root開始

JVM進階

哪些可以作為GC Roots的對象:從它們作為垃圾掃描的起始點

  • 虛拟機棧(棧幀中的局部變量區,也叫局部變量表)中引用的對象;
  • 方法區中的類靜态屬性引用的對象;
  • 方法區中的常量引用的對象;
  • 本地方法棧中JNI(Native方法)引用的對象;

 2.JVM參數類型:

①标配參數(java -version、java -help、java -showversion);

②x參數(了解;-Xint解釋執行、-Xcomp第一次使用就編譯成本地代碼、-Xmixed混合模式即先編譯後執行) ;

C:\Users\Administrator>java -Xint -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, interpreted mode)

C:\Users\Administrator>java -Xcomp -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, compiled mode)      

View Code

③xx參數

  ③.1 Boolean類型:

  公式 -XX:+或者-某個屬性值(+表示開啟,-表示關閉)

  Case:①是否列印GC收集細節 -XX:-PrintGCDetails、-XX:+PrintGCDetails

     ②是否使用串行垃圾收集器:-XX:-UseSerialGC  ; -XX:+UseSerialGC

E:\20181111\javaSE\JUCJVM>jps -l
7456 sun.tools.jps.Jps
6292 org.jetbrains.idea.maven.server.RemoteMavenServer
6676 com.atguigu.jvm.gc.HelloGc
6868 org.jetbrains.jps.cmdline.Launcher

E:\20181111\javaSE\JUCJVM>jinfo -flag PrintGCDetails 6676
-XX:-PrintGCDetails

在IDEA中添加參數:
VM option: -XX:+PrintGCDetails 
再次重複上邊的步驟則:
-XX:+PrintGCDetails 就已經開啟了      

  ③.2 kv設值類型 公式:-XX:屬性key=屬性值value

JVM進階
E:\20181111\javaSE\JUCJVM>jinfo -flag PrintGCDetails 7284  //在開啟+PrintGCDetails之上,檢視MetaspaceSize的大小,預設上22M左右
-XX:+PrintGCDetails

E:\20181111\javaSE\JUCJVM>jinfo -flag MetaspaceSize 7284
-XX:MetaspaceSize=21807104
E:\20181111\javaSE\JUCJVM>jinfo -flag  MaxTenuringThreshold 7284
-XX:MaxTenuringThreshold=15


同理可在ieda中配置參數設定它的值
-XX:MetaspaceSize=1024M
E:\20181111\javaSE\JUCJVM>jinfo -flag MetaspaceSize 8058
-XX:MetaspaceSize=1073741824      

  ③.3 jinfo舉例,如何檢視目前運作程式的配置

    公式:jinfo -flag 配置項 程序編号    Command line是人工設定的

E:\20181111\javaSE\JUCJVM>jinfo -flags 4292
Attaching to process ID 4292, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.141-b15
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4269801472 -XX:MaxNewSize=1422917632 -XX:MetaspaceS
ize=1073741824 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
 -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -XX:MetaspaceSize=1024M -javaagent:D:\ProgramFiles\ideaIU\ideaIU-2018.1.4\lib\idea_rt.jar=52146:D:\ProgramFiles\ideaIU\ideaIU-
2018.1.4\bin -Dfile.encoding=UTF-8        

兩個經典參數:-Xms <==> -XX:InitialHeapSize;-Xmx  <==> -XX:MaxHeapSize

Xms 初始的堆空間;  Xmx 堆空間最大值  ;它倆最好調成一樣,避免GC頻繁的收集 忽高忽低;

Xss初始的棧空間

 盤點家底檢視JVM預設值:

-XX:+PrintFlagsInitial        
-XX:+PrintFlagsFinal  PrintFlagsFinal舉例,運作java指令的同時列印出參數
      
-XX:+PrintCommandLineFlags      

-Xms系統記憶體的1/64、-Xmx系統記憶體的1/4

檢視初始預設值: java -XX:+PrintFlagsInitial
      
java -XX:+PrintFlagsFinal -version      
①
E:\20181111\javaSE\JUCJVM>java -XX:+PrintFlagsInitial  //這個參數很重要!JVM系統預設的
[Global flags]
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
    uintx AdaptiveSizePausePolicy                   = 0                                   {product}
    uintx AdaptiveSizePolicyCollectionCostMargin    = 50                                  {product}
    uintx AdaptiveSizePolicyInitializingSteps       = 20                                  {product}
    uintx AdaptiveSizePolicyOutputInterval          = 0                                   {product}
    uintx AdaptiveSizePolicyWeight                  = 10                                  {product}
    uintx AdaptiveSizeThroughPutPolicy              = 0                                   {product}
    uintx AdaptiveTimeWeight                        = 25                                  {product}
     bool AdjustConcurrency                         = false                               {product}
     bool AggressiveOpts                            = false                               {product}      
②
java -XX:+PrintFlagsFinal -version這個是會列印出JVM的版本 ;Final是修改過最終的值 ;Initial是初始預設的
                                              =是沒改過, :=是人為或JVM加載不一樣自己去修改過;
  uintx MaxHeapSize                   := 4269801472                 {product} ##這些加:=表示修改過之後的值;沒有加:表沒有修改
 uintx InitialHeapSize                          := 268435456                           {product}      
JVM進階

java -XX:+PrintFlagsFinal   -XX:MetaspaceSize=512m T(運作java類名字)

③ 
C:\Users\Administrator>java -XX:+PrintCommandLineFlags -version  //主要用來檢視預設的垃圾回收器 
-XX:InitialHeapSize=266841920 -XX:MaxHeapSize=4269470720 -XX:+PrintCommandLineFl
ags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesInd
ividualAllocation -XX:+UseParallelGC //檢視預設的垃圾回收器的種類
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)      

3.JVM基本配置參數有哪些?

堆記憶體的初始配置設定

常用參數:

-Xms:初始大小記憶體,預設為實體記憶體1/64;等價于  -XX:InitialHeapSize

-Xmx:最大配置設定記憶體,預設為實體記憶體1/4; 等價于  -XX:MaxHeapSize

-Xss:設定單個線程棧大小,一般預設為512k--1024k  -XX:ThreadStackSize  運作時棧空間

-Xmn: 設定年輕代大小

-XX:MetaspaceSize:

典型設定案例:

-XX:+PrintGCDetails 輸出詳細GC收集日志資訊; GC;  FullGC

-XX:SurvivorRatio:

-XX:NewRatio

-XX:MaxTenuringThreshold

E:\20181111\javaSE\JUCJVM>jinfo -flag ThreadStackSize 8852 //0表示預設配置,是根據系統的配置
-XX:ThreadStackSize=0

E:\20181111\javaSE\JUCJVM>jps -l
4560 sun.tools.jps.Jps
6292 org.jetbrains.idea.maven.server.RemoteMavenServer
3032 org.jetbrains.jps.cmdline.Launcher
5368
7192 com.atguigu.jvm.gc.HelloGc
在IDEA中配置-Xss128k 

E:\20181111\javaSE\JUCJVM>jinfo -flag ThreadStackSize 7192
-XX:ThreadStackSize=128      
JVM進階

 -Xmm一般不調用的預設值,new 新生代 年輕代;

-XX:MetaspaceSize 

設定元空間大小,元空間本質和永久代類似,都是對JVM規範中方法區的實作;不過元空間與永久代之間最大的差別在于:元空間并不在虛拟機中,而是使用本地記憶體。

是以,預設情況下,元空間的大小僅受本地記憶體限制。-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m

-Xms10m -Xmx 10m  -XX:MetaspaceSize=1024m -XX:+PrintFlagsFinal 

E:\20181111\javaSE\JUCJVM>jinfo -flag MetaspaceSize 7188
-XX:MetaspaceSize=21807104  //元空間預設大小約是21M
可以自己配置;自定義      

典型設定案例:

在IDEA中配置:VM options:-XX:+PrintCommandLineFlags
預設:
-XX:InitialHeapSize=266841920 
-XX:MaxHeapSize=4269470720 
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC 
************HelloWorld

-XX:+UseParallelGC 并行垃圾回收器
-XX:+UseSerialGC  串行垃圾回收器


在IDEA中配置:VM options:
-Xms128m -Xmx4096m -Xss1024k -XX:MetaspaceSize=512m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC
-XX:InitialHeapSize=134217728 
-XX:MaxHeapSize=4294967296 
-XX:MetaspaceSize=536870912 
-XX:+PrintCommandLineFlags 
-XX:+PrintGCDetails 
-XX:ThreadStackSize=1024 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseSerialGC 
************HelloWorld      
************HelloWorld
//配置設定失敗,沒有空間了壓縮産生了次GC
GC在新生區,Full GC在養老區
[GC (Allocation Failure) [PSYoungGen: 1960K->488K(2560K)(GC前是1960,GC後是488k,新生區總共2560K)] 1960K->768K(9728K)(GC之前堆是1960,之後是768K,9728是堆的總大小), 0.0029644 secs(GC耗時時間)] [Times: user=0.08 sys=0.00, real=0.00 secs] (GC使用者時間、系統時間、GC實際時間)
[GC (Allocation Failure) [PSYoungGen: 488K->496K(2560K)] 768K->856K(9728K), 0.0031208 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

[Full GC (Allocation Failure) [PSYoungGen: 496K->0K(2560K)] [ParOldGen: 360K->640K(7168K)] 856K->640K(9728K), [Metaspace: 3439K->3439K(1056768K)], 0.0079096 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 640K->640K(9728K), 0.0004159 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 640K->621K(7168K)] 640K->621K(9728K), [Metaspace: 3439K->3439K(1056768K)], 0.0053786 secs] [Times: user=0.09 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 2560K, used 96K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 4% used [0x00000000ffd00000,0x00000000ffd183c0,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 7168K, used 621K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 8% used [0x00000000ff600000,0x00000000ff69b7d8,0x00000000ffd00000)
 Metaspace       used 3484K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space      
JVM進階
JVM進階
JVM進階

 -XX:SurvivorRatio

設定新生代中eden和S0/S1空間的比例,預設-XX:SurvivorRatio=8,Eden:S0:S1 = 8:1:1

假如 -XX:SurvivorRatio=4,Eden:S0:S1 = 4:1:1,SurvivorRatio值就是設定eden區的比例占多少,S0/S1相同;

Eden:S0:S1 = 8:1:1
-XX:+PrintGCDetails  -XX:+UseSerialGC -Xms10m -Xmx10m -XX:SurvivorRatio=8 // -XX:SurvivorRatio=8加不加結果沒影響
  eden space 2752K,  74% used [0x00000000ff600000, 0x00000000ff803fe8, 0x00000000ff8b0000)
  from space 320K,   0% used [0x00000000ff8b0000, 0x00000000ff8b0000, 0x00000000ff900000) //320 * 8 大約= 2752
  to   space 320K,   0% used [0x00000000ff900000, 0x00000000ff900000, 0x00000000ff950000)
 tenured generation   total 6848K, used 0K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000)
   the space 6848K,

Eden:S0:S1 = 4:1:1
-XX:+PrintGCDetails  -XX:+UseSerialGC -Xms10m -Xmx10m -XX:SurvivorRatio=4
  eden space 2368K,  85% used [0x00000000ff600000, 0x00000000ff7f84d8, 0x00000000ff850000)
  from space 512K,   0% used [0x00000000ff850000, 0x00000000ff850000, 0x00000000ff8d0000)
  to   space 512K,   0% used [0x00000000ff8d0000, 0x00000000ff8d0000, 0x00000000ff950000)
 tenured generation   total 6848K, used 0K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000)
   the space 6848K,      

 -XX:NewRatio 

預設年輕代與老年代在堆結構的占比 預設 -XX:NewRatio = 2新生代占1,老年代占2,年輕代占整個堆的1/3;

                假如 -XX:NewRatio = 4新生代占1,老年代占4,年輕代占整個堆的1/5,NewRatio值就是設定老年代的占比,剩下的1給新生代;

設定新生代和老年代比例:
-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:+UseSerialGC -XX:NewRatio=2 預設的

-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:+UseSerialGC -XX:NewRatio=4
 def new generation   total 1856K, used 477K [0x00000000ff600000, 0x00000000ff800000, 0x00000000ff800000)
 tenured generation   total 8192K, used 431K [0x00000000ff800000, 0x0000000100000000, 0x0000000100000000)       

-XX:MaxTenuringThreshold=15

垃圾最大年齡不能超過15

JVM進階

強應用、軟引用、弱引用、虛引用分别是什麼?

JVM進階

①強引用

JVM進階
public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = obj1;
        obj1 = null;
        System.gc();
        System.out.println(obj1); //null
    }      

②軟引用

軟引用:記憶體足夠的前提下不收,記憶體不夠時收;強引用:死了都不收;

JVM進階

 ③ 弱引用:不管記憶體是否夠用, 隻要有GC一定回收

JVM進階
JVM進階
public class WeekHashMapDemo {
    public static void main(String[] args) {
        myHashMap();
        System.out.println("===================");
        myWeekHashMap();

    }
    private static void myWeekHashMap() {
        WeakHashMap<Integer, String> weekHashMap = new WeakHashMap<>();

        Integer key = new Integer(2);
        String value = "weekHashMap";
        weekHashMap.put(key, value);
        System.out.println(weekHashMap); //{2=weekHashMap}

        key = null;
        System.out.println(weekHashMap); //{2=weekHashMap}

        System.gc();
        System.out.println(weekHashMap + "\t" + weekHashMap.size()); //{}    0
    }
    private static void myHashMap() {
        HashMap<Integer, String> hashMap = new HashMap<>();
        Integer key = new Integer(1); //這裡的key指向的是一個Integer的引用
        String value = "HashMap";
        hashMap.put(key, value); //HashMap中的put放的是Node類型的K V鍵值對
        System.out.println(hashMap); //{1=HashMap}

        key = null; //key是否是null無所謂,跟HashMap沒關系,Node的key的節點沒有變化
        System.out.println(hashMap); //{1=HashMap}

        System.gc();
        System.out.println(hashMap + "\t" + hashMap.size()); //{1=HashMap} 1
    }
}      

④ 虛引用:

JVM進階
JVM進階

引用隊列

弱引用在GC時候會被裝到引用隊列中

public class PhantomReferenceDemo {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); //引用隊列
        PhantomReference<Object> phantomReference = new PhantomReference<>(obj, referenceQueue);

        System.out.println(obj); //java.lang.Obj[email protected]
        System.out.println(phantomReference.get()); //null,它的get方法總是傳回null,無法通路對象的引用對象
        System.out.println(referenceQueue.poll()); //null

        System.out.println("==================");
        obj = null;
        System.gc();
        Thread.sleep(500);

        System.out.println(obj); //null
        System.out.println(phantomReference.get()); //null
        System.out.println(referenceQueue.poll()); //[email protected]

    }
}      
JVM進階
JVM進階

OOM:

java.lang.StackOverflowError      
java.lang.OutOfMemoryError: Java heap space      
java.lang.OutOfMemoryError: GC overhead limit exceeded      
java.lang.OutOfMemoryError: Direct buffer memory      
java.lang.OutOfMemoryError: unable to create new native thread
      
java.lang.OutOfMemoryError: Metaspace      
JVM進階

① 棧記憶體溢出:深度的方法調用 java.lang.StackOverflowError

public class StackOverFlowDemo {
    public static void main(String[] args) {
        stackOverFlowError();
    }

    public static void stackOverFlowError(){
        stackOverFlowError(); //Exception in thread "main" java.lang.StackOverflowError
    }
    /*
    這個叫錯誤,不是異常;
throwable是所有異常和錯誤的父類
java.lang.Object
    java.lang.Throwable
        java.lang.Error
            java.lang.VirtualMachineError
                java.lang.StackOverflowError

     */
}      

 ② 堆記憶體溢出;對象太多了 Error   java.lang.OutOfMemoryError: Java heap space

public class JavaHeapSpaceErrorDemp {
    public static void main(String[] args) {
/*        String str = "kris";
        while (true){
            str += str + new Random().nextInt(11111111) + new Random().nextInt(2222222);
            str.intern();
        }*/
        byte[] bytes = new byte[90 * 1024 * 1024];//90M
        //Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    }
}      

java.lang.OutOfMemoryError: GC overhead limit exceeded

JVM參數配置示範:-Xms10m -Xmx10m  -XX:MaxDirectMemorySize=5m

GC回收時間過長會抛出OutOfMemroyError;過長的定義是:超過98%的時間用來做GC并且回收了不到2%的堆記憶體;連續多次GC都隻回收了不到2%的極端情況下才會抛出,假如不抛出GC overhead limit錯誤會發生什麼情況呢?那就是GC清理的這麼點記憶體很快會再次填滿,迫使GC再次執行,這樣就形成惡性循環,CPU使用率一直是100%,而GC卻沒有任何成果。

JVM進階
//-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:MaxDirectMemorySize=5m 
public class GCOverHeadDemo {
    public static void main(String[] args) {
        int i = 0;
        List<String> list = new ArrayList<>();
        try {
            while (true){
                list.add(String.valueOf(++i).intern());
            }
        } catch (Throwable e) {
            System.out.println("***********i:" + i); // java.lang.OutOfMemoryError: GC overhead limit exceeded
            e.printStackTrace();  //***********i:145444
            throw e;
        }
    }
}      

java.lang.OutOfMemoryError: Direct buffer memory

配置參數: -Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:MaxDirectMemorySize=5m

 導緻原因:寫NIO程式(非阻塞)經常使用ByteBuffer來讀取或者寫入資料,這是一種基于通道Channel與緩沖區Buffer的I/O方式,它可以使用Native函數庫直接配置設定堆外記憶體,然後通過一個存儲在Java堆裡面的
DirectByteBuffer對象作為這塊記憶體的引用進行操作。這樣能在一些場景中顯著提高性能,因為避免了在java堆和Native堆中來回複制資料。
ByteBuffer.allocate(capability)第一種方式是配置設定JVM堆記憶體,屬于GC管轄範圍,由于需要拷貝是以速度相對較慢;
ByteBuffer.allocate(capability)第二種方式是配置設定OS本地記憶體,不屬于GC管轄範圍,由于不需要記憶體拷貝是以速度相對較快;
但如果不斷配置設定本地記憶體,堆記憶體很快使用,那麼JVM就不需要執行GC,DirectByteBuffer對象們就不會被回收,這時候堆記憶體充足,但本地記憶體很快使用光了,再次嘗試配置設定本地記憶體出出現
OutOfMemoryError,那麼程式就直接崩潰了。      

java\jre\lib\rt.jar(它會回去加載String、Object等,放到元空間保證java一開始就可以用)    rt.jar \sun\misc\VM.class

直接記憶體溢出:

JVM進階
public class DirectBufferMemoryDemo {
    //-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:MaxDirectMemorySize=5m
    public static void main(String[] args) {
        System.out.println("配置的maxDirectMemory" + (sun.misc.VM.maxDirectMemory() / (double)1024/ 1024 )+ "MB");
         try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
        //-XX:MaxDirectMemorySize=5m
         ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6* 1024 * 1024);
         // Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory

    }
}      
高并發請求伺服器時經常出現的異常:java.lang.OutOfMemoryError: unable to create new native thread
準确的講該native thread異常與對應的平台有關;      

 導緻原因:

①你的應用建立了太多線程,一個應用程序建立多個線程,超過系統承載極限;

②你的伺服器并不允許你的應用程式建立這麼多線程,linux系統預設允許建立的線程數是1024個,你的應用建立超過這個數量,就會報 java.lang.OutOfMemoryError: unable to create new native thread

解決辦法:

①想辦法降低你應用程式建立線程的數量,分析應用是否真的需要建立這麼多線程,如果不是,改代碼将線程數降到最低;

②對于有的應用,确實需要建立多線程,遠超過linux系統的預設1024個線程的限制,可以通過修改linux伺服器配置,擴大linux預設配置;

*************i = 4072
*************i = 4073
*************i = 4074
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
        at java.lang.Thread.start0(Native Method)
        at java.lang.Thread.start(Thread.java:717)
        at UnableCreateNewThreadDemo.main(UnableCreateNewThreadDemo.java:9)
       
JVM進階

create new native thread :①非root使用者登入Linux系統測試; ②伺服器級别調參調優;

JVM進階
JVM進階
[[email protected] ~]$ ulimit -u
4096

[[email protected] ~]$ vim /etc/security/limits.d/90-nproc.conf 
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

*          soft    nproc     4096
root       soft    nproc     unlimited      
使用java -XX:+PrintFlagsInitial指令檢視本機的初始化參數,-XX:MetaspaceSize為21810376B(大約為20.8M)      
C:\Users\Administrator>java -XX:+PrintFlagsInitial
......
intx MaxTrivialSize                            = 6                                   {product}
     intx MaxVectorSize                             = 32                                  {C2 product}
    uintx MetaspaceSize                             = 21810376                            {pd product}
     bool MethodFlushing                            = true                                {product}
    uintx MinHeapDeltaBytes                         = 170392                              {product}
    uintx MinHeapFreeRatio                          = 40                                  {manageable}
     intx MinInliningThreshold                      = 250                                 {product}
     intx MinJumpTableSize                          = 10                                  {C2 pd product}
    uintx MinMetaspaceExpansion                     = 340784                              {product}
    uintx MinMetaspaceFreeRatio                     = 40                                  {product}
    uintx MinRAMFraction                            = 2                                   {product}      
JVM進階
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

;import java.lang.reflect.Method;
//-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
public class MetaspaceSizeOOMDemo {
    static class OOMTest{}
    public static void main(String[] args) {
        int i = 0;
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, args);
                    }
                });
                enhancer.create();
            }
        }catch (Throwable e){
            System.out.println("**********多少次發生了異常: " + i);
            e.printStackTrace();
        }
            //**********多少次發生了異常: 282
        //java.lang.OutOfMemoryError: Metaspace

    }

}      

轉載于:https://www.cnblogs.com/shengyang17/p/10801453.html

繼續閱讀