記憶體結構圖
GC作用域
常見的垃圾回收算法:
①引用計數:有對象引用就加1,沒對象引用就減1,到0為止回收; 雙端循環引用特别容易報錯;
應用:微軟COM/ActionScrip3/Python...
缺點:每次對對象指派時均要維護引用計數器,且計數器本身也有一定的消耗; 較難處理循環引用; ===> JVM的實作一般不采用這種方式。
②複制:用在新生代;幸存者0區和幸存者1區,GC時會進行交換;複制--清空--交換; 優點是沒有産生記憶體碎片(整體複制),缺點是有點浪費空間;
③标記清除:标記---清除,會産生碎片 ;;
④标記整理: 既不浪費空間又不産生碎片但它耗時很長;
③④用于老年代比較多
GC Root
記憶體中已經不再被使用到的空間就是垃圾;要進行垃圾回收如何判斷一個對象是否可以被回收?
①引用計數法:
Java中,引用和對象是有關聯的。如果要操作對象則必須用引用進行; 通過引用計數來判斷一個對象是否可以回收,即給對象添加一個引用計數器,當有一個地方引用它,計數器值加1,當有一個引用實效時,計數器值減1。任何時刻計數器值為0的對象就是不可能再被使用的,那麼這個對象就是可回收對象。
但主流java虛拟機裡都沒采用這種算法,因為它很難解決對象之間互相循環引用的問題。(了解即可)
枚舉根節點做可達性分析(根搜尋路徑)
為了解決引用計數法的循環引用問題,java使用了可達性分析的方法。
所謂"GC Roots"或者說tracing GC的“根集合” 就是一組必須活躍的引用。
基本思路就是通過一系列名為"GC Roots"的對象作為起始點,從這個被稱為GC Roots的對象開始向下搜尋,如果一個對象到GC Roots沒有任何引用鍊相連時,則說明此對象不可用。也即給定一個集合的引用作為根出發,通過引用關系周遊對象圖,能被周遊到的(可到達)對象就被判定為存活;沒有被周遊到的就自然被判定為死亡。
可達性分析/ 根搜尋路徑:從GC Root開始
哪些可以作為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
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}
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
-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
-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
強應用、軟引用、弱引用、虛引用分别是什麼?
①強引用
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = obj1;
obj1 = null;
System.gc();
System.out.println(obj1); //null
}
②軟引用
軟引用:記憶體足夠的前提下不收,記憶體不夠時收;強引用:死了都不收;
③ 弱引用:不管記憶體是否夠用, 隻要有GC一定回收
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
}
}
④ 虛引用:
引用隊列
弱引用在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]
}
}
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
① 棧記憶體溢出:深度的方法調用 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卻沒有任何成果。
//-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
直接記憶體溢出:
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)
create new native thread :①非root使用者登入Linux系統測試; ②伺服器級别調參調優;
[[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}
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