阈值和垃圾收集器类型对于对象分配的影响实战分析
//打印JVM的一些默认参数
C:\***\***>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=199142400 //初始的堆大小
-XX:MaxHeapSize=3186278400 //堆最大容量
-XX:+PrintCommandLineFlags //打印命令行的相关启动信息
-XX:+UseCompressedClassPointers //使用压缩的类指针
-XX:+UseCompressedOops //从32位的虚拟机上迁移到64位的虚拟机上,会对指针进行相应的压缩处理
-XX:-UseLargePagesIndividualAllocation // 什么意思?
-XX:+UseParallelGC //决定了新生代、老年代使用什么样的垃圾收集器
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
参数设置:
//(1)当新创建的对象的大小已经超过了PretenureSizeThreshold这个阈值,那么就不会在新生代去创建,而直接在老年代进行内存的分配 //(2)PretenureSizeThreshold要搭配的是串行收集器(单线程收集器serial) -XX:PretenureSizeThreshold=4194304 //4M //虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial+Serial Old的收集器组合进行内存回收 -XX:+UseSerialGC
实例:
-verbose:gc
-Xms20M
-Xmx20M
-Xmn10M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:PretenureSizeThreshold=4194304 //4M
-XX:+UseSerialGC
public class MyTest2 {
public static void main(String[] args) {
int size = 1024 * 1024;
byte[] myAlloc = new byte[5 * size];
}
}
// 下面的运行结果可以,在设置了阈值为4M之后,由于myAlloc的字节数位5M,所以直接进入到了老年代used 5120K
// def new generation
// tenured generation
运行结果:
Heap
def new generation total 9216K, used 5249K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 64% used [0x00000000fec00000, 0x00000000ff120618, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 5120K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 50% used [0x00000000ff600000, 0x00000000ffb00010, 0x00000000ffb00200, 0x0000000100000000)
Metaspace used 3314K, capacity 4568K, committed 4864K, reserved 1056768K
class space used 361K, capacity 392K, committed 512K, reserved 1048576K
这里出现一个问题:
在阈值还是4M,将参数-XX:+UseSerialGC去掉之后,byte[] myAlloc = new byte[5 * size],张龙老师中的运行结果是: used OK,老年代没有生效,但是我这里的运行结果是:可以在老年代中正常分配内存空间:
通过jvisualvm和jmc查看GC情况:
public class MyTest2 {
public static void main(String[] args) {
int size = 1024 * 1024;
byte[] myAlloc = new byte[5 * size];
try {
Thread.sleep(100000);
}catch (InterruptedException e){
e.printStackTrace();;
}
}
}
通过jmc和jcmd 查看启动参数:
-
通过jcmd查看:【先通过jps -l查看端口号,再通过jcmd 11444 VM.flags查看相应的参数】
-
在jmc的飞行计数器中查看分配信息:
-
下面这个是去掉-XX:+UseSerialGC这行参数所显示的: