1. JVM概述
JVM是一个支持在不同操作系统上执行Java字节码的运行时容器, 拥有内存管理/垃圾回收等功能.
Java字节码无法直接执行, JVM需要将其翻译成机器码.
在HotSpot里, 该翻译过程有两种形式:
-
解释执行: 逐条将字节码翻译成机器码.
-
即时编译执行: 将一个方法中所有的字节码翻译成机器码后再执行.
HotSpot内置多种编译器:
-
C1
启动块,编译时间短 -
C2
编译时间比较长,但执行效率高 -
graal
2. Class文件组成
-
magic number
-
minor&major versions
-
constant pool
-
access flags
-
this class
-
super class
-
interfaces
-
fields
-
methods
-
attributes
3. 类加载器
3.1. 获取类加载器的方法
-
获取某一个类所属的类加载器:
Class::getClassLoader()
-
获取APP类加载器:
ClassLoader.getSystemClassLoader()
-
获取当前线程上下文使用的类加载器:
Thread.currentThread().getContextClassLoader()
3.2. BootstrapClassLoader
启动类加载器.
本身使用C/C++实现, 没有父加载器.
通过 sun.misc.Launcher.getBootstrapClassPath().getURLs()
获取加载类的路径.
3.3. ExtClassLoader
加载jre/lib/ext子目录下的类库, 父加载器为BootstrapClassLoader.
通过 System.getProperty("java.ext.dirs")
获取加载类的路径.
3.4. AppClassLoader
加载classpath/java.class.path路径下的类库, 是应用程序默认的类加载器.
父加载器为ExtClassLoader.
3.5. 用户自定义类加载器
-
修改类加载的方式.
-
隔离加载类.
-
扩展加载源.
-
防止源码泄露.
-
继承
ClassLoader
类, 覆盖loadClass()
方法. -
继承
URLClassLoader
类.
3.6. 双亲委派机制
加载某个类的class文件时, 把请求委托给父加载器处理.
如果父加载器无法加载, 则子加载器才会自己去加载.
-
避免类的重复加载.
-
防止jdk核心类的篡改.
-
DriverManager属于JDK下的类, 但从线程上下文取到
AppClassLoader
去加载数据库厂商的JDBC Driver获取链接. -
Tomcat使用WebAppClassLoader自己先尝试加载类, 加载不到再去找父类加载.
4. 类加载的过程
4.1. 加载
-
通过一个类的全限定名获取定义此类的二进制字节流.
-
将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构.
-
在内存中生成一个代表这个类的
java.lang.Class
对象, 作为方法区这个类的各种数据的访问入口.
4.2. 链接
链接分为 验证, 准备, 解析 三个阶段.
确保字节流符合当前虚拟机要求, 保证类加载的正确性.
验证文件格式/元数据/字节码/符号引用.
为静态变量分配零值(null/0).
常量设置初始值.
解析符号引用为直接引用.
4.3. 初始化
执行类构造器方法 clinit()
, 该方法是由javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来.
-
创建类的实例.
-
访问类的静态变量, 或者对该变量赋值.
-
调用类的静态方法.
-
反射.
Class.forName("FQCN")
-
加载一个类的子类.
-
JVM启动时作为启动入口的类.
-
通过MethodHandler解析的类.
5. JVM内存布局
红色代表线程共享, 灰色代表线程私有.
5.1. PC
存储下一条要执行的指令的地址.
如果在执行的是native方法, 则值为undefined.
5.2. 虚拟机栈
每个线程在创建时都会创建一个虚拟机栈, 栈中的数据以栈帧的格式存在.
在这个线程上执行的每个方法都各自对应一个栈帧.
栈顶的栈帧对应的就是当前正在执行的方法, 如果该方法调用了其他方法, 则创建出一个新的栈帧并入栈.
方法执行完或抛出异常时当前栈帧会出栈.
-
局部变量表(方法内部局部变量字节码行号和变量名的映射关系.)
-
操作数栈(在方法执行过程中保存计算结果的临时存储空间. 操作数栈的大小
max_stack
在编译时就会确定好, 保存在方法的Code属性中.) -
动态链接(指向运行时常量池的方法引用.)
-
方法返回地址(存放调用该方法的pc寄存器的值.)
-
…
线程请求分配的栈容量超过JVM允许的最大容量, JVM会抛出 StackOverflowError
.
如果Java虚拟机栈在尝试扩展的时候申请不到足够的内存, 或者创建新的线程时没有足够的内存去创建对应的虚拟机栈, JVM会抛出 OutOfMemoryError
.
// java.lang.StackOverflowError
private static void stackOverflow() {
stackOverflow();
}
// java.lang.OutOfMemoryError: unable to create new native thread
private static void createInfiniteThread() {
while (true) {
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(100L);
} catch (InterruptedException ignored) {
}
}).start();
}
}
5.3. 本地方法栈
管理本地方法的调用.
5.4. 方法区
存储类的结构信息, 运行时常量池, JIT编译后的代码等等.
5.5. 堆
存储对象实例.
5.5.1. OOM异常类型
-
Java heap space
-
GC overhead limit exceeded
-
PermGen space
-
Metaspace
-
Unable to create new native thread
-
Out of swap space
-
Requested array size exceeds VM limit
-
Kill process or sacrifice child
-
reason stack_trace_with_native_method
-
Direct Buffer Memory
-
Map failed
6. JDK常用工具
6.1. jcmd
打印Java进程所涉及的基本类, 线程和VM信息
jcmd <pid> <command> [args]
-
jcmd 9914 VM.system_properties
查看JVM进程properties -
jcmd 9914 VM.uptime
查看JVM进程运行时间 -
jcmd 9914 VM.version
查看JVM版本 -
jcmd 9914 VM.command_line
查看JVM启动命令 -
jcmd 9914 VM.flags
查看JVM启动参数 -
jcmd 9914 Thread.print
查看JVM线程栈信息 -
jcmd 9914 GC.run
手动执行一次FullGC. -
jcmd 9914 GC.heap_info
查看对内存区域占用. -
jcmd 9914 GC.heap_dump
dump内存.
6.2. jps
查看系统运行的所有Java进程的pid
-
-q
只打印JVM进程id. -
-m
打印main方法执行参数. -
-l
打印启动类全限定名或者启动jar包的文件路径. -
-v
打印JVM启动参数.
6.3. jinfo
查看指定Java进程信息
jinfo [option] <pid>
-
jinfo -flags 1
查看pid为1的进程的所有启动参数 -
jinfo -flag UseCompressedOops 9914
查看指定参数
6.5. jstat
jstat [option] <pid> [interval] [times]
查看指定进程的内存使用及GC概况. 如: jstat -gcutil 6451 1000
每隔1秒输出进程6451的概况
-
S0
第一个survivor区容量使用率 -
S1
第二个survivor区容量使用率 -
E
Eden区容量使用率 -
O
Old区容量使用率 -
M
Metaspace区容量使用率 -
YGC
young gc次数 -
YGCT
young gc总耗时 -
FGC
full gc次数 -
FGCT
full gc总耗时 -
GCT
gc总耗时
6.6. jmap
查看指定进程的堆内存使用情况.
jmap [option] <pid>
-
-heap
查看堆内存的配置和使用信息. -
-histo
查看各个类实例的数量和占用的内存大小. -
-dump:format=b;file=xxx.hprof
dump堆内存.
6.7. javap
查看class字节码文件
javap <class file>
-
-c: 反编译class
-
-p: 显示
private
方法和字段 -
-v: 显示详细信息
-
-s: 显示类型签名
-
-l: 输出行号和本地变量表
-
-sysinfo: 显示类的系统信息
7. JVM参数
7.1. 参数分类
JVM主要接受两类标志: boolean类和赋值类参数.
-
boolean类:
-XX:+FLAG_NAME
.
如:-XX:+UseCompressedOops
开启64位JVM中的对象引用压缩,-XX:-UseCompressedOops
关闭压缩. -
赋值类:
-XX:+FLAG_NAME=VALUE
.
如-XX:AutoBoxCacheMax=20000
. -
简写类.
如-Xms -Xmx -Xmn -Xss
查看所有可选标志: java -XX:+PrintFlagsFinal -version
|
7.2. 常用启动参数
-
-XX:+UseSerialGC
使用Serial+Serial Old组合回收新生代和老年代. -
-XX:+UseParNewGC
使用ParNew+Serial Old组合回收新生代和老年代. -
-XX:+UseConcMarkSweepGC
使用ParNew+CMS组合回收新生代和老年代, 当出现 Concurrent Mode Failure 后使用Serial Old回收老年代. -
-XX:+UseParallelGC
使用Parallel Scavenge+Serial Old组合回收新生代和老年代. -
-XX:+UseParallelOldGC
使用Parallel Scavenge+Parallel Old组合回收新生代和老年代. -
-XX:+UseG1GC
使用G1回收堆内存. -
-XX:+UseZGC
使用ZGC回收堆内存. -
-XX:+UseShenandoahGC
使用ShenandoahGC回收堆内存, 只能在OpenJDK12及以上版本中使用.
-
-XX:+PrintGC
输出GC简要日志. -
-XX:+PrintGCDetails
输出gc详细日志. -
-XX:+PrintHeapAtGC
输出GC前后堆和方法区容量大小. -
-XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime
输出GC与用户线程并发时间以及GC停顿时间. -
-XX:+PrintAdaptiveSizePolicy
查看JVM堆各个分代大小自动调节信息. -
-XX:+PrintTenuringDistribution
查看GC后剩余对象的年龄分布信息. -
-Xloggc:<FILENAME> -XX:+UseGCLogfileRotation -XX:NumberOfGCLogfiles=N -XX:GCLogfileSize=N
gc日志写入指定文件并切割.
-Xlog[:[what][:[output][:[decorators][:output-options[,…]]]]]
-
-Xlog:gc
输出GC简要日志. -
-Xlog:gc*
输出GC详细日志. -
-Xlog:gc+heap=debug
输出GC前后堆和方法区容量大小. -
-Xlog:safepoint
输出GC与用户线程并发时间以及GC停顿时间. -
-Xlog:gc+ergo*=trace
查看JVM堆各个分代大小自动调节信息. -
-Xlog:gc+age=trace
查看GC后剩余对象的年龄分布信息. -
-Xlog:gc*:file=<file>::filecount=<count>,filesize=<sizekb>
gc日志写入指定文件并切割.
-
-XX:SurvivorRatio=8
新生代中 Eden 区和 Survivor 区的比例, 默认为8, 及 8:1:1 . -
-XX:PretenureSizeThreshold=0
直接晋升到老年代的对象大小, 大于这个参数的对象将直接在老年代上分配. -
-XX:MaxTenuringThreshold=15
晋升到老年代的对象年龄, 每个对象在 Minor GC 后年龄加一, 当年龄超过这个参数后会进入老年代. -
-XX:+UseAdaptiveSizePolicy
(不推荐) 动态调整堆中各个区域的大小以及老年代的年龄. -
-XX:ParallelGCThreads=8
设置并行GC时进行内存回收的线程数. -
-XX:GCTimeRatio=N
设置应用运行时间占比: \$"Throughput"="GCTimeRatio"/(1+"GCTimeRatio")\$ -
-XX:MaxGCPauseMillis=N
设定应用可承受的最大停顿时间.一般设置为200, 如果设置的值过小, 会导致老年代非常小, 从而频繁进行 Full GC . -
-XX:CMSInitiatingOccupancyFraction=68
设置CMS收集器在老年代空间被使用多少后触发垃圾回收, 默认为68%. -
-XX:+UseCMSCompactAtFullCollection
设置CMS在 Full GC 后是否进行内存碎片整理. [Java9后废弃] -
-XX:CMSFullGCsBeforeCompaction=0
设置CMS在多少次 Full GC 后进行内存碎片整理. [Java9后废弃] -
-XX:G1HeapRegionSize=0
设置G1 Region大小. -
-XX:G1NewSizePercent=5
设置G1新生代最小值, 默认为5%. -
-XX:G1MaxNewSizePercent=60
设置G1新生代最大值, 默认为60%. -
-XX:InitiatingHeapOccupancyPercent=45
设置触发标记周期的堆(old+humongous)占用阈值, 默认为45%.
8. 内存分配策略
8.1. 内存分配方式
-
指针碰撞: 所有被使用的内存放一边, 空闲的内存放一边, 维护一个指针标识两部分内存的分界线, 使用标记-整理的垃圾回收器会使用指针碰撞的分配方式.
-
空闲列表: 虚拟机维护一个列表, 记录哪些内存块是可用的, 哪些是不可用的, 使用标记-清除的垃圾回收器会使用空闲列表的分配方式.
8.2. 对象优先在Eden区分配
大多数情况下, 对象在栈上或者新生代Eden区中分配.
当Eden区没有足够空间进行分配时, 虚拟机将发起一次 Minor GC .
8.3. 大对象直接进入老年代
需要大量连续内存空间的Java对象(如数组), 直接在老年代分配.
虚拟机提供了 -XX:PretenureSizeThreshold
参数指定大于该参数值的对象直接在老年代分配.
8.4. 长期存活的对象进入老年代
对象如果在 Minor GC 后仍然存活, 并能被Survivor区容纳, 则移动到Survivor区, 年龄加1. 年龄超过 MaxTenuringThreshold
参数后, 下次 Minor GC 时会进入老年代.
8.5. 老年代空间分配担保
Minor GC 之前, 虚拟机会先检查老年代最大可用的连续空间是否大于等于新生代所有对象总空间或者大于等于历史晋升的平均大小, 如果大于则进行 Minor GC , 否则将直接进行 Full FC .
9. 垃圾收集算法
9.1. 复制
将内存按容量划分为大小相等的两块, 每次只用其中的一块.
当某一块的内存用完了, 就将还存活的的对象复制到另外一块上, 然后再把已使用过的内存空间一次清理掉.
-
为对象分配内存时不需要考虑内存碎片的问题.
-
可用内存只有一半.
-
如果对象的存活率高, 则拷贝对象的操作开销比较大.
-
Serial/ParNew收集器使用复制算法收集新生代.
9.2. 标记整理
让所有存活的对象向内存空间一端移动, 然后直接清理掉边界以外的内存.
-
没有内存碎片
-
移动对象的开销大.
-
Serial Old/Parallel Old使用标记-整理算法收集老年代.
9.3. 标记清除
首先标记出所有需要回收的对象, 在标记完成后统一回收所有被标记的对象.
-
相对于复制算法节省了内存空间.
-
执行效率不稳定, 如果内存中大量对象需要被回收, 则必须进行大量标记和清除的动作.
-
导致内存碎片化.
-
CMS使用标记清除算法回收老年代.
10. GC分类
-
Minor GC/Young GC: 新生代的收集.
-
Major GC/Old GC: 老年代的收集.(CMS)
-
Mixed GC: 收集整个新生代和部分老年代的过程.(G1)
-
Full GC: 整个Java堆和方法区的收集.
11. GC Root
-
虚拟机栈和本地方法栈中本地变量表引用的对象.
-
方法区中静态属性引用的对象.
-
方法区中常量引用的对象.
-
虚拟机内部的类引用的对象, 比如JDK官方的类Class对象或者类加载器.
-
被同步锁持有的对象.
12. 垃圾收集器
垃圾收集分两步: 在为对象分配内存时遇到内存不足, 查找不再使用的对象, 然后释放这些对象所在的内存.
由于对象的生存时间不同, 所有的垃圾收集器都采用分代收集的方式.
堆内存被划分为 新生代 (Young Generation)和 老年代 (Old Generation或Tenured Generation), 默认空间占比 1:2. 新生代又被分为一个Eden区和两个Survivor区.
默认空间占比 8:1:1.
-
对象首先尝试在栈上分配, 栈空间不够时在新生代Eden区分配.
-
Eden区填满时 , 垃圾收集器会暂停所有应用线程回收新生代(垃圾收集时所有应用线程停止运行所产生的停顿称为 STW (stop-the-world)).此时不再使用的对象会被回收, 仍在使用的对象会移动到Survivor区或老年代, 这一过程称为 Minor GC . 由于所有的存活对象都被移走, 此时相当于在新生代做了一次整理.
-
单独回收老年代的过程称为 Major GC . (CMS)
-
回收新生代和一部分老年代的过程称为 Mixed GC .(G1)
-
对象不断移动到老年代, 等到 老年代空间占满 , JVM会回收整个堆, 这一过程称为 Full GC .
12.1. Serial
Serial垃圾收集器使用 单线程 回收内存, 垃圾回收时会暂停所有的用户线程.
使用 -XX:+UseSerialGC
启用Serial垃圾收集器.
-
新生代
Serial
使用复制算法, GC时会暂停所有用户线程. -
老年代
Serial Old
使用标记-整理算法, GC时暂停所有用户线程.
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xmx500m -XX:+UseSerialGC GCLogAnalysis
2020-10-27T20:27:43.434-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.434-0800: [DefNew: 69870K->8703K(78656K), 0.0146897 secs] 69870K->23463K(253440K), 0.0147228 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] (1)
2020-10-27T20:27:43.475-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.475-0800: [DefNew: 78655K->8704K(78656K), 0.0219163 secs] 93415K->43153K(253440K), 0.0219731 secs] [Times: user=0.01 sys=0.01, real=0.02 secs]
2020-10-27T20:27:43.518-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.518-0800: [DefNew: 78656K->8704K(78656K), 0.0268356 secs] 113105K->68112K(253440K), 0.0268698 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
2020-10-27T20:27:43.573-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.573-0800: [DefNew: 78656K->8703K(78656K), 0.0283694 secs] 138064K->86737K(253440K), 0.0284128 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
2020-10-27T20:27:43.633-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.633-0800: [DefNew: 78655K->8704K(78656K), 0.0204895 secs] 156689K->110372K(253440K), 0.0205465 secs] [Times: user=0.01 sys=0.01, real=0.02 secs]
2020-10-27T20:27:43.675-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.675-0800: [DefNew: 78656K->8698K(78656K), 0.0295495 secs] 180324K->135983K(253440K), 0.0295976 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
2020-10-27T20:27:43.719-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.719-0800: [DefNew: 78650K->8704K(78656K), 0.0269409 secs] 205935K->161503K(253440K), 0.0269808 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
2020-10-27T20:27:43.758-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.758-0800: [DefNew: 78553K->8703K(78656K), 0.0247593 secs]2020-10-27T20:27:43.783-0800: [Tenured: 174929K->161954K(174976K), 0.0382564 secs] 231353K->161954K(253632K), [Metaspace: 5478K->5478K(1056768K)], 0.0632989 secs] [Times: user=0.05 sys=0.01, real=0.07 secs] (2)
2020-10-27T20:27:43.858-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.858-0800: [DefNew: 108096K->13439K(121536K), 0.0261365 secs] 270050K->199412K(391464K), 0.0261749 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
2020-10-27T20:27:43.910-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.910-0800: [DefNew: 121535K->13430K(121536K), 0.0407543 secs] 307508K->233687K(391464K), 0.0407952 secs] [Times: user=0.05 sys=0.03, real=0.04 secs]
2020-10-27T20:27:43.979-0800: [GC (Allocation Failure) 2020-10-27T20:27:43.979-0800: [DefNew: 121526K->13439K(121536K), 0.0282363 secs] 341783K->266291K(391464K), 0.0282747 secs] [Times: user=0.01 sys=0.01, real=0.03 secs]
2020-10-27T20:27:44.033-0800: [GC (Allocation Failure) 2020-10-27T20:27:44.033-0800: [DefNew: 121417K->13432K(121536K), 0.0318451 secs]2020-10-27T20:27:44.065-0800: [Tenured: 290446K->241497K(290448K), 0.0549298 secs] 374268K->241497K(411984K), [Metaspace: 5478K->5478K(1056768K)], 0.0869765 secs] [Times: user=0.07 sys=0.02, real=0.09 secs]
2020-10-27T20:27:44.137-0800: [GC (Allocation Failure) 2020-10-27T20:27:44.137-0800: [DefNew: 136419K->17022K(153600K), 0.0244343 secs] 377916K->287817K(494976K), 0.0244742 secs] [Times: user=0.01 sys=0.01, real=0.03 secs]
2020-10-27T20:27:44.188-0800: [GC (Allocation Failure) 2020-10-27T20:27:44.188-0800: [DefNew: 153167K->17023K(153600K), 0.0434442 secs] 423962K->328060K(494976K), 0.0435019 secs] [Times: user=0.02 sys=0.02, real=0.05 secs]
2020-10-27T20:27:44.249-0800: [GC (Allocation Failure) 2020-10-27T20:27:44.249-0800: [DefNew: 153599K->153599K(153600K), 0.0000215 secs]2020-10-27T20:27:44.249-0800: [Tenured: 311036K->293415K(341376K), 0.0753151 secs] 464636K->293415K(494976K), [Metaspace: 5478K->5478K(1056768K)], 0.0754695 secs] [Times: user=0.07 sys=0.00, real=0.08 secs]
2020-10-27T20:27:44.351-0800: [GC (Allocation Failure) 2020-10-27T20:27:44.351-0800: [DefNew: 136576K->17022K(153600K), 0.0170228 secs] 429991K->341321K(494976K), 0.0170677 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2020-10-27T20:27:44.385-0800: [GC (Allocation Failure) 2020-10-27T20:27:44.385-0800: [DefNew: 153598K->153598K(153600K), 0.0000162 secs]2020-10-27T20:27:44.385-0800: [Tenured: 324298K->300756K(341376K), 0.0832796 secs] 477897K->300756K(494976K), [Metaspace: 5478K->5478K(1056768K)], 0.0833456 secs] [Times: user=0.08 sys=0.00, real=0.08 secs]
Heap
def new generation total 153600K, used 5917K [0x00000007a0c00000, 0x00000007ab2a0000, 0x00000007ab2a0000)
eden space 136576K, 4% used [0x00000007a0c00000, 0x00000007a11c75b0, 0x00000007a9160000)
from space 17024K, 0% used [0x00000007aa200000, 0x00000007aa200000, 0x00000007ab2a0000)
to space 17024K, 0% used [0x00000007a9160000, 0x00000007a9160000, 0x00000007aa200000)
tenured generation total 341376K, used 300756K [0x00000007ab2a0000, 0x00000007c0000000, 0x00000007c0000000)
the space 341376K, 88% used [0x00000007ab2a0000, 0x00000007bd8553b0, 0x00000007bd855400, 0x00000007c0000000)
Metaspace used 5492K, capacity 5958K, committed 6016K, reserved 1056768K
class space used 595K, capacity 626K, committed 640K, reserved 1048576K
1 | 本次为YoungGC, Young区总大小为78656K, 整个堆总大小为253440K, GC后Young区使用量从69870K降到了8703K, 整个堆使用量从69870K降到了23463K. |
2 | 本次为FullGC, Young区总大小为78656K, Old区总大小为174976K, 整个堆总大小为253632K, GC后Young区使用量从78553K降到了8703K, Old区使用量从174929K降到了161954K, 整个堆使用量从231353K降到了161954K. |
12.2. Parallel
JDK8默认收集器. |
Parallel垃圾收集器使用 多线程 并行回收内存, 垃圾回收时会暂停所有的用户线程.
使用 -XX:+UseParallelGC
启用Parallel垃圾收集器.
-
新生代
Parallel Scavenge
使用复制算法, GC时暂停所有用户线程. -
老年代
Parallel Old
使用标记-整理算法, GC时暂停所有用户线程.
-
-XX:MaxGCPauseMills
收集器将尽力保证内存回收花费的时间不包括这个设定的值. -
-XX:GCTimeRatio
垃圾收集时间占总时间的占比. 默认99. -
-XX:+UseAdaptiveSizePolicy
JVM根据当前系统的运行信息自动调节-Xmn/-XX:SurvivorRatio/-XX:PretenureSizeThreshold
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xmx500m -XX:+UseParallelGC GCLogAnalysis
2020-10-27T20:31:42.234-0800: [GC (Allocation Failure) [PSYoungGen: 65536K->10732K(76288K)] 65536K->27190K(251392K), 0.0121700 secs] [Times: user=0.01 sys=0.05, real=0.01 secs] (1)
2020-10-27T20:31:42.274-0800: [GC (Allocation Failure) [PSYoungGen: 76208K->10749K(141824K)] 92666K->51153K(316928K), 0.0158102 secs] [Times: user=0.02 sys=0.07, real=0.02 secs]
2020-10-27T20:31:42.359-0800: [GC (Allocation Failure) [PSYoungGen: 141821K->10751K(141824K)] 182225K->92844K(316928K), 0.0271800 secs] [Times: user=0.04 sys=0.11, real=0.03 secs]
2020-10-27T20:31:42.425-0800: [GC (Allocation Failure) [PSYoungGen: 141823K->10751K(159744K)] 223916K->140207K(334848K), 0.0303295 secs] [Times: user=0.04 sys=0.13, real=0.03 secs]
2020-10-27T20:31:42.455-0800: [Full GC (Ergonomics) [PSYoungGen: 10751K->0K(159744K)] [ParOldGen: 129455K->126304K(263680K)] 140207K->126304K(423424K), [Metaspace: 5486K->5486K(1056768K)], 0.0292847 secs] [Times: user=0.13 sys=0.00, real=0.03 secs] (2)
2020-10-27T20:31:42.527-0800: [GC (Allocation Failure) [PSYoungGen: 148992K->10751K(159744K)] 275296K->177754K(423424K), 0.0274459 secs] [Times: user=0.05 sys=0.10, real=0.03 secs]
2020-10-27T20:31:42.591-0800: [GC (Allocation Failure) [PSYoungGen: 159743K->10743K(67584K)] 326746K->226687K(331264K), 0.0304457 secs] [Times: user=0.05 sys=0.11, real=0.03 secs]
2020-10-27T20:31:42.621-0800: [Full GC (Ergonomics) [PSYoungGen: 10743K->0K(67584K)] [ParOldGen: 215944K->188313K(341504K)] 226687K->188313K(409088K), [Metaspace: 5486K->5486K(1056768K)], 0.0271394 secs] [Times: user=0.12 sys=0.00, real=0.02 secs]
2020-10-27T20:31:42.669-0800: [GC (Allocation Failure) [PSYoungGen: 56258K->16332K(113664K)] 244572K->204646K(455168K), 0.0024383 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2020-10-27T20:31:42.687-0800: [GC (Allocation Failure) [PSYoungGen: 73164K->32564K(113664K)] 261478K->220878K(455168K), 0.0075769 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
2020-10-27T20:31:42.709-0800: [GC (Allocation Failure) [PSYoungGen: 88659K->47677K(113664K)] 276972K->235991K(455168K), 0.0078832 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
2020-10-27T20:31:42.736-0800: [GC (Allocation Failure) [PSYoungGen: 104509K->36972K(113664K)] 292823K->254875K(455168K), 0.0100647 secs] [Times: user=0.05 sys=0.01, real=0.01 secs]
2020-10-27T20:31:42.772-0800: [GC (Allocation Failure) [PSYoungGen: 93415K->18147K(113664K)] 311317K->271321K(455168K), 0.0249421 secs] [Times: user=0.03 sys=0.09, real=0.02 secs]
2020-10-27T20:31:42.806-0800: [GC (Allocation Failure) [PSYoungGen: 74947K->19445K(113664K)] 328122K->289146K(455168K), 0.0093222 secs] [Times: user=0.02 sys=0.02, real=0.01 secs]
2020-10-27T20:31:42.831-0800: [GC (Allocation Failure) [PSYoungGen: 76277K->17627K(113664K)] 345978K->305371K(455168K), 0.0089946 secs] [Times: user=0.02 sys=0.03, real=0.01 secs]
2020-10-27T20:31:42.854-0800: [GC (Allocation Failure) [PSYoungGen: 74459K->16959K(113664K)] 362203K->321770K(455168K), 0.0116318 secs] [Times: user=0.03 sys=0.04, real=0.01 secs]
2020-10-27T20:31:42.866-0800: [Full GC (Ergonomics) [PSYoungGen: 16959K->0K(113664K)] [ParOldGen: 304811K->241616K(341504K)] 321770K->241616K(455168K), [Metaspace: 5486K->5486K(1056768K)], 0.0484392 secs] [Times: user=0.23 sys=0.01, real=0.05 secs]
2020-10-27T20:31:42.930-0800: [GC (Allocation Failure) [PSYoungGen: 56669K->22742K(113664K)] 298286K->264359K(455168K), 0.0036387 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:31:42.943-0800: [GC (Allocation Failure) [PSYoungGen: 79574K->18280K(113664K)] 321191K->281473K(455168K), 0.0054439 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
2020-10-27T20:31:42.967-0800: [GC (Allocation Failure) [PSYoungGen: 75074K->20044K(113664K)] 338267K->300845K(455168K), 0.0054350 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
2020-10-27T20:31:42.989-0800: [GC (Allocation Failure) [PSYoungGen: 76850K->23313K(113664K)] 357652K->322762K(455168K), 0.0099082 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
2020-10-27T20:31:43.008-0800: [GC (Allocation Failure) [PSYoungGen: 80105K->16903K(113664K)] 379553K->338875K(455168K), 0.0191813 secs] [Times: user=0.05 sys=0.06, real=0.02 secs]
2020-10-27T20:31:43.027-0800: [Full GC (Ergonomics) [PSYoungGen: 16903K->0K(113664K)] [ParOldGen: 321971K->272257K(341504K)] 338875K->272257K(455168K), [Metaspace: 5486K->5486K(1056768K)], 0.0505424 secs] [Times: user=0.24 sys=0.00, real=0.05 secs]
2020-10-27T20:31:43.096-0800: [GC (Allocation Failure) [PSYoungGen: 56243K->22017K(113664K)] 328500K->294275K(455168K), 0.0045945 secs] [Times: user=0.02 sys=0.01, real=0.01 secs]
2020-10-27T20:31:43.110-0800: [GC (Allocation Failure) [PSYoungGen: 78849K->18143K(113664K)] 351107K->311726K(455168K), 0.0061414 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
2020-10-27T20:31:43.130-0800: [GC (Allocation Failure) [PSYoungGen: 74971K->16293K(113664K)] 368555K->325547K(455168K), 0.0059918 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
2020-10-27T20:31:43.136-0800: [Full GC (Ergonomics) [PSYoungGen: 16293K->0K(113664K)] [ParOldGen: 309254K->287559K(341504K)] 325547K->287559K(455168K), [Metaspace: 5486K->5486K(1056768K)], 0.0510250 secs] [Times: user=0.24 sys=0.00, real=0.05 secs]
Heap
PSYoungGen total 113664K, used 28277K [0x00000007b5980000, 0x00000007c0000000, 0x00000007c0000000)
eden space 56832K, 49% used [0x00000007b5980000,0x00000007b751d4e0,0x00000007b9100000)
from space 56832K, 0% used [0x00000007bc880000,0x00000007bc880000,0x00000007c0000000)
to space 56832K, 0% used [0x00000007b9100000,0x00000007b9100000,0x00000007bc880000)
ParOldGen total 341504K, used 287559K [0x00000007a0c00000, 0x00000007b5980000, 0x00000007b5980000)
object space 341504K, 84% used [0x00000007a0c00000,0x00000007b24d1cb0,0x00000007b5980000)
Metaspace used 5499K, capacity 5958K, committed 6016K, reserved 1056768K
class space used 595K, capacity 626K, committed 640K, reserved 1048576K
1 | 本次为YoungGC, Young区总大小为76288K, 整个堆总大小为251392K, GC后Young区使用量从65536K降到了10732K, 整个堆使用量从65536K降到了27190K. |
2 | 本次为FullGC, Young区总大小为159744K, Old区总大小为263680K, 整个堆总大小为423424K, GC后Young区使用量从10751K降到了0K, Old区使用量从129455K降到了126304K, 整个堆使用量从140207K降到了126304K. |
12.3. ParNew
Serial垃圾收集器使用 多线程 回收 新生代内存 (线程数等于CPU数), 垃圾回收时会暂停所有的应用线程.
使用 -XX:+UseParNewGC
启用ParNew垃圾收集器.
通常与CMS搭配使用.
-
新生代
ParNew
使用复制算法, GC时会暂停所有用户线程.
12.4. CMS
JDK14被移除. |
CMS使用多线程并发回收老年代内存, 使用 -XX:+UseConcMarkSweepGC
启用CMS收集器.
-
初始标记: 单线程标记一下
GC Roots
对象. -
并发标记: 从
GC Roots
对象开始遍历整个对象图. -
重新标记: 修正并发标记期间, 因用户程序继续运作而导致标记变动的那部分对象的标记记录.
-
并发清除: 清除那些被标记为死亡的对象.
阶段1和阶段3会暂停所有用户线程, 阶段2和阶段4GC线程可以和用户线程并发执行.
CMS回收并发线程数默认是 \$("nCPU"+3)/4\$ .
-
-XX:CMSInitiatingOccupancyFraction
老年代占用超过这个阈值后会触发CMS回收内存. -
-XX:+UseCMSCompactAtFullCollection
在Full GC时开启内存碎片的合并. -
-XX:CMSFullGCsBeforeCompaction
在执行指定次数不整理空间的Full FC后, 在下一次Full GC前整理内存碎片. -
-XX:+CMSScavengeBeforeRemark
在CMS重新标记阶段前触发Young GC
.
-
YoungGC导致Young区对象晋升到Old区, 但是Old区没有足够容量收纳晋升过来的对象, 此时触发FullGC, 在GC日志中标识为
promotion failed
.-
解决办法: 增大Young区大小.
-
-
CMS并发标记阶段应用线程会产生一部分新的可回收对象( 浮动垃圾 ), 且分配新的对象内存的时候可能因为内存不足触发FullGC, 在GC日志中标识为
concurrent mode failure
.-
解决办法: 让Old区提前回收(-XX:CMSInitiatingOccupancyFraction), 或者每次CMS GC后整理下内存(-XX:+UseCMSCompactAtFullCollection).
-
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xmx500m -XX:+UseConcMarkSweepGC GCLogAnalysis
2020-10-27T20:39:17.104-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.104-0800: [ParNew: 69952K->8698K(78656K), 0.0093642 secs] 69952K->22083K(253440K), 0.0094129 secs] [Times: user=0.02 sys=0.04, real=0.01 secs] (1)
2020-10-27T20:39:17.141-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.141-0800: [ParNew: 78650K->8698K(78656K), 0.0087938 secs] 92035K->39298K(253440K), 0.0088282 secs] [Times: user=0.02 sys=0.03, real=0.01 secs]
2020-10-27T20:39:17.174-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.174-0800: [ParNew: 78650K->8703K(78656K), 0.0225999 secs] 109250K->60847K(253440K), 0.0227016 secs] [Times: user=0.12 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.218-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.218-0800: [ParNew: 78324K->8704K(78656K), 0.0192211 secs] 130467K->82592K(253440K), 0.0192581 secs] [Times: user=0.11 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.267-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.267-0800: [ParNew: 78656K->8702K(78656K), 0.0162077 secs] 152544K->107316K(253440K), 0.0162478 secs] [Times: user=0.10 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.283-0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 98614K(174784K)] 108733K(253440K), 0.0001820 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] (2)
2020-10-27T20:39:17.283-0800: [CMS-concurrent-mark-start] (3)
2020-10-27T20:39:17.285-0800: [CMS-concurrent-mark: 0.002/0.002 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.285-0800: [CMS-concurrent-preclean-start] (4)
2020-10-27T20:39:17.286-0800: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.286-0800: [CMS-concurrent-abortable-preclean-start] (5)
2020-10-27T20:39:17.304-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.304-0800: [ParNew: 78654K->8700K(78656K), 0.0146260 secs] 177268K->129456K(253440K), 0.0146893 secs] [Times: user=0.09 sys=0.01, real=0.01 secs]
2020-10-27T20:39:17.340-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.340-0800: [ParNew: 78652K->8698K(78656K), 0.0170268 secs] 199408K->150863K(253440K), 0.0170998 secs] [Times: user=0.11 sys=0.00, real=0.01 secs]
2020-10-27T20:39:17.372-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.372-0800: [ParNew: 78397K->8702K(78656K), 0.0147147 secs] 220562K->172577K(253440K), 0.0147697 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]
2020-10-27T20:39:17.407-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.407-0800: [ParNew: 78368K->8702K(78656K), 0.0148902 secs] 242243K->195716K(266244K), 0.0149562 secs] [Times: user=0.09 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.443-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.443-0800: [ParNew: 78654K->8703K(78656K), 0.0261878 secs] 265668K->223486K(294104K), 0.0262856 secs] [Times: user=0.15 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.490-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.491-0800: [ParNew: 78655K->8703K(78656K), 0.0269818 secs] 293438K->244642K(315344K), 0.0271319 secs] [Times: user=0.13 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.530-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.530-0800: [ParNew: 78467K->8700K(78656K), 0.0222884 secs] 314407K->269319K(339980K), 0.0224062 secs] [Times: user=0.14 sys=0.02, real=0.02 secs]
2020-10-27T20:39:17.572-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.572-0800: [ParNew: 78652K->8697K(78656K), 0.0280387 secs] 339271K->293670K(364248K), 0.0281057 secs] [Times: user=0.17 sys=0.02, real=0.03 secs]
2020-10-27T20:39:17.611-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.611-0800: [ParNew: 78338K->8702K(78656K), 0.0207492 secs] 363311K->316144K(386844K), 0.0208035 secs] [Times: user=0.12 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.661-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.661-0800: [ParNew: 78654K->8703K(78656K), 0.0168668 secs] 386096K->337852K(408460K), 0.0169848 secs] [Times: user=0.11 sys=0.00, real=0.01 secs]
2020-10-27T20:39:17.679-0800: [CMS-concurrent-abortable-preclean: 0.016/0.393 secs] [Times: user=1.55 sys=0.15, real=0.39 secs]
2020-10-27T20:39:17.679-0800: [GC (CMS Final Remark) [YG occupancy: 17167 K (78656 K)]2020-10-27T20:39:17.679-0800: [Rescan (parallel) , 0.0009628 secs]2020-10-27T20:39:17.680-0800: [weak refs processing, 0.0000274 secs]2020-10-27T20:39:17.680-0800: [class unloading, 0.0008790 secs]2020-10-27T20:39:17.681-0800: [scrub symbol table, 0.0008922 secs]2020-10-27T20:39:17.682-0800: [scrub string table, 0.0002329 secs][1 CMS-remark: 329149K(329804K)] 346317K(408460K), 0.0031208 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] (6)
2020-10-27T20:39:17.682-0800: [CMS-concurrent-sweep-start] (7)
2020-10-27T20:39:17.683-0800: [CMS-concurrent-sweep: 0.001/0.001 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.683-0800: [CMS-concurrent-reset-start] (8)
2020-10-27T20:39:17.684-0800: [CMS-concurrent-reset: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.700-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.701-0800: [ParNew: 78302K->78302K(78656K), 0.0000177 secs]2020-10-27T20:39:17.701-0800: [CMS: 318914K->241056K(341376K), 0.0705879 secs] 397217K->241056K(420032K), [Metaspace: 5484K->5484K(1056768K)], 0.0708164 secs] [Times: user=0.09 sys=0.00, real=0.07 secs]
2020-10-27T20:39:17.772-0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 241056K(341376K)] 241603K(494976K), 0.0002567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.772-0800: [CMS-concurrent-mark-start]
2020-10-27T20:39:17.774-0800: [CMS-concurrent-mark: 0.002/0.002 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.774-0800: [CMS-concurrent-preclean-start]
2020-10-27T20:39:17.775-0800: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.775-0800: [CMS-concurrent-abortable-preclean-start]
2020-10-27T20:39:17.827-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.827-0800: [ParNew: 136576K->17017K(153600K), 0.0153041 secs] 377632K->289227K(494976K), 0.0153775 secs] [Times: user=0.10 sys=0.01, real=0.02 secs]
2020-10-27T20:39:17.871-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.871-0800: [ParNew: 153593K->17022K(153600K), 0.0170277 secs] 425803K->336041K(494976K), 0.0170661 secs] [Times: user=0.12 sys=0.01, real=0.01 secs]
2020-10-27T20:39:17.891-0800: [CMS-concurrent-abortable-preclean: 0.005/0.116 secs] [Times: user=0.36 sys=0.05, real=0.12 secs]
2020-10-27T20:39:17.891-0800: [GC (CMS Final Remark) [YG occupancy: 22623 K (153600 K)]2020-10-27T20:39:17.891-0800: [Rescan (parallel) , 0.0016173 secs]2020-10-27T20:39:17.893-0800: [weak refs processing, 0.0000399 secs]2020-10-27T20:39:17.893-0800: [class unloading, 0.0023604 secs]2020-10-27T20:39:17.896-0800: [scrub symbol table, 0.0010799 secs]2020-10-27T20:39:17.897-0800: [scrub string table, 0.0002871 secs][1 CMS-remark: 319019K(341376K)] 341642K(494976K), 0.0056143 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.897-0800: [CMS-concurrent-sweep-start]
2020-10-27T20:39:17.899-0800: [CMS-concurrent-sweep: 0.001/0.001 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.899-0800: [CMS-concurrent-reset-start]
2020-10-27T20:39:17.899-0800: [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.920-0800: [GC (Allocation Failure) 2020-10-27T20:39:17.920-0800: [ParNew: 153598K->153598K(153600K), 0.0000383 secs]2020-10-27T20:39:17.920-0800: [CMS: 318202K->283658K(341376K), 0.0618453 secs] 471801K->283658K(494976K), [Metaspace: 5484K->5484K(1056768K)], 0.0619482 secs] [Times: user=0.06 sys=0.00, real=0.06 secs]
2020-10-27T20:39:17.982-0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 283658K(341376K)] 286702K(494976K), 0.0002134 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.982-0800: [CMS-concurrent-mark-start]
2020-10-27T20:39:17.984-0800: [CMS-concurrent-mark: 0.002/0.002 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.984-0800: [CMS-concurrent-preclean-start]
2020-10-27T20:39:17.985-0800: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:17.985-0800: [CMS-concurrent-abortable-preclean-start]
2020-10-27T20:39:18.007-0800: [GC (Allocation Failure) 2020-10-27T20:39:18.007-0800: [ParNew: 136576K->17023K(153600K), 0.0083199 secs] 420234K->331289K(494976K), 0.0083692 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
2020-10-27T20:39:18.017-0800: [CMS-concurrent-abortable-preclean: 0.002/0.032 secs] [Times: user=0.08 sys=0.00, real=0.03 secs]
2020-10-27T20:39:18.017-0800: [GC (CMS Final Remark) [YG occupancy: 29614 K (153600 K)]2020-10-27T20:39:18.017-0800: [Rescan (parallel) , 0.0004149 secs]2020-10-27T20:39:18.017-0800: [weak refs processing, 0.0000117 secs]2020-10-27T20:39:18.017-0800: [class unloading, 0.0009162 secs]2020-10-27T20:39:18.018-0800: [scrub symbol table, 0.0007536 secs]2020-10-27T20:39:18.019-0800: [scrub string table, 0.0001732 secs][1 CMS-remark: 314265K(341376K)] 343879K(494976K), 0.0023383 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:18.019-0800: [CMS-concurrent-sweep-start]
2020-10-27T20:39:18.020-0800: [CMS-concurrent-sweep: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2020-10-27T20:39:18.020-0800: [CMS-concurrent-reset-start]
2020-10-27T20:39:18.020-0800: [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:18.040-0800: [GC (Allocation Failure) 2020-10-27T20:39:18.040-0800: [ParNew: 153599K->153599K(153600K), 0.0000214 secs]2020-10-27T20:39:18.040-0800: [CMS: 314265K->309716K(341376K), 0.0750800 secs] 467865K->309716K(494976K), [Metaspace: 5484K->5484K(1056768K)], 0.0751629 secs] [Times: user=0.08 sys=0.00, real=0.07 secs]
2020-10-27T20:39:18.116-0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 309716K(341376K)] 312690K(494976K), 0.0002100 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-10-27T20:39:18.116-0800: [CMS-concurrent-mark-start]
ִcounter:6777
Heap
par new generation total 153600K, used 5705K [0x00000007a0c00000, 0x00000007ab2a0000, 0x00000007ab2a0000)
eden space 136576K, 4% used [0x00000007a0c00000, 0x00000007a1192510, 0x00000007a9160000)
from space 17024K, 0% used [0x00000007aa200000, 0x00000007aa200000, 0x00000007ab2a0000)
to space 17024K, 0% used [0x00000007a9160000, 0x00000007a9160000, 0x00000007aa200000)
concurrent mark-sweep generation total 341376K, used 309716K [0x00000007ab2a0000, 0x00000007c0000000, 0x00000007c0000000)
Metaspace used 5499K, capacity 5958K, committed 6016K, reserved 1056768K
class space used 595K, capacity 626K, committed 640K, reserved 1048576K
1 | 本次为YoungGC, Young区总大小为78656K, 整个堆总大小为253440K, GC后Young区使用量从69952K降到了8698K, 整个堆使用量从69952K降到了22083K. |
2 | CMS开始MinorGC, 此时Old区占用98614K/174784K, 整个堆占用108733K/253440K, 本次为开始标记阶段, 会暂停所有用户线程. |
3 | 并发标记阶段, 与用户线程并发执行. |
4 | 预清理阶段, 与用户线程并发执行. |
5 | 可中断预清理阶段, 等待上一次YoungGC结束一段时间后再准备开始下一个阶段(为了防止YoungGC和最终标记连续暂停用户线程两次). |
6 | 最终标记阶段, 此时暂停用户线程0.01秒. |
7 | 并发清除阶段, 开始回收老年代, 此时GC线程与用户线程并发执行. |
8 | 并发重置阶段. |
12.5. G1
JDK9默认收集器 |
使用 -XX:+UseG1GC
启动G1收集器.
12.5.1. Region
G1将堆划分为多个大小相等的独立区域, 每个区域可以根据需要扮演Eden/Survivor/Old/Humongous空间.
每个region大小限制在1MB~32MB之间, 通过 -XX:G1HeapRegionSize
参数指定.
如果不指定, 则默认为 min(32MB, max(round(Xmx/2048), 1MB))
, 如果计算出来超过32MB.
12.5.2. CardTable
CardTable是用来记录跨代引用关系的数据结构( point-out
: 描述我指向谁). JVM全局维护一个bitmap数组, 大小为Xmx/512B, 每一位标识地址在 n*512
到 (n+1)*512-1
区域的内存页.
如果该区域存在Old区引用Young区对象则为1, 否则为0.
12.5.3. RememberSet
每个region存在一个RememberSet, 存储有哪些Region引用当前Region的对象, 以及这些指针在CardTable的范围内.
如old区obj1.field = Young区的obj2, 则obj2所处的region的RememberSet会记录obj1所处region的地址, 以及obj1在region中的card索引号(从0开始).
12.5.4. 三色标记
在标记过程中从GC Root对象开始遍历所有引用对象, 使用三种颜色标识对象是否需要回收:
-
黑色: 表示对象及其所有引用已被遍历过, 且该对象存活. 如果有其他对象引用该黑色对象, 则无需再次遍历.
-
灰色: 表示对象被遍历到, 但其还有引用对象没被遍历到.
-
白色: 表示对象没被遍历到, 即对象不可达需要被回收.
12.5.5. 并发标记
原始快照(SATB): 为解决并发标记过程中Mutator线程修改了遍历中或者遍历过的对象引用, 在并发标记过程中, 将灰色对象被Mutator线程删除白色对象引用时记录下该灰色对象, 待并发标记阶段结束后,
再重新遍历一次灰色对象及其 原始的 引用对象集合.
12.5.6. G1主要回收流程
-
遍历RootSet和Young区的RememberSet对象.
-
将根对象和RememberSet中的对象和他们引用的对象复制到Survivor区.
-
清理Eden和CardTable, 重新构建Young区的RememberSet.
-
初始标记(STW): 标记
GC Roots
对象. -
并发标记: 从
GC Roots
对象开始遍历整个对象图(三色标记: 黑色为存活对象, 灰色为遍历中对象, 白色为待回收对象). -
最终标记(STW): 修正并发标记期间, 因用户程序继续运作而导致标记变动的那部分对象的标记记录.
-
筛选回收(STW): 计算每个待回收old region的代价找到回收收益最高的若干region, 和所有的young region一起回收, 将存活下来的对象复制到空的Region中再清空原来的Region.
13. GC调优
13.1. 选择恰当的垃圾收集器
-
数据分析/科学计算类应用, 关注吞吐量.
ParallelGC
-
事务型应用, 关注低延迟.
CMS/G1/ZGC
-
客户端/嵌入式设备应用, 关注内存占用.
Serial
13.2. 永远不要把堆内存的大小设置的比机器物理内存大
推荐 -Xms=-Xmx=80%机器内存, -XX:NewRatio=1.
Full GC时JVM会访问整个堆的内容, 内存交换会拖慢GC的速度. 使用-Xms和-Xmx分别设置堆内存的最小值和最大值.
默认64位JVM堆内存初始值为取512MB和物理内存大小1/64二者中的最小值, 最大值取32G和物理内存大小1/4二者中的最小值.
13.3. 调整新生代与老年代的大小
-
G1GC不设置Xmn, 让JVM自动调整新生代和老年代的大小
-
新生代大小设置参数, 后者优先级更高
-
-XX:NewRatio 设置新生代与老年代的比例, 默认值为2. 默认情况下新生代大小初始值等于
初始堆大小/(1+NewRatio)
-
-XX:NewSize 设置新生代大小的初始值
-
-XX:MaxNewSize 设置新生代大小的最大值
-
-Xmn 同时设置新生代的初始值和最大值
-
13.4. 记录GC日志以便分析
示例: -Xlog:gc*:file=logs/gc-%t.log:time,tags:filecount=20,filesize=20M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs
14. 调试JDK源码
-
下载openjdk源码:
git clone https://github.com/openjdk/jdk.git
-
设置机器上当前使用的jdk(Boot JDK)版本为最新的发布版本.
-
编译jdk:
-
bash configure --with-debug-level=slowdebug
-
make all
-
等待编译结束, build目录下会生成jdk目录.
-
make compile-commands
-
-
导入项目到CLION:
-
点击open, 选择编译好的jdk目录下的
compile_commands.json
文件. -
Tools → Compilation Database → Change Project Root
选择源码目录. -
Custom Build Targets
新增配置make和clean命令组合:-
Program:
make
, Arguments:CONF=编译好的jdk目录名
, Working directory:源码目录
. -
Program:
make
, Arguments:CONF=编译好的jdk目录名 clean
, Working directory:源码目录
.
-
-
Run/Debug Configurations
新增Custom Build Application
, Target选择上一步创建的Build命令组合, Executable 选择编译好的java
可执行文件, Program Arguments 填想要运行的Java类全限定名, Working directory 填想要运行的Java类所在目录.
-
-
设置debug环境:
echo "breakpoint set --file /path/to/jdk/src/java.base/share/native/launcher/main.c --line 98 -C "pro hand -p true -s false SIGSEGV SIGBUS" --auto-continue true" | tee ~./.lldbinit