内存结构图
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)
③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.Object@14ae5a5 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()); //java.lang.ref.PhantomReference@7f31245a } }
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系统测试; ②服务器级别调参调优;
[kris@hadoop101 ~]$ ulimit -u 4096 [kris@hadoop101 ~]$ 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 } }