文章目录
- 1. 垃圾回收器分类
- 2. 不同垃圾回收器概述
- 3. Serial与Serial Old垃圾回收器:串行回收
- 4. ParNew垃圾回收器:并行回收
- 5. Parallel与Parallel Old垃圾回收器:吞吐量优先
- 6. CMS回收器:低延迟
- 7. G1回收器:区域分代式
- 8. 垃圾回收器总结
- 9. GC日志分析
- 10. 垃圾回收器的新发展
1. 垃圾回收器分类
评估GC的性能指标
2. 不同垃圾回收器概述
jdk8中,UseParallelGC默认搭配UseParallelOldGC
修改idea中程序运行的JDK版本
3. Serial与Serial Old垃圾回收器:串行回收
4. ParNew垃圾回收器:并行回收
ParNew底层与Serial共用了大量的代码
5. Parallel与Parallel Old垃圾回收器:吞吐量优先
6. CMS回收器:低延迟
7. G1回收器:区域分代式
G1回收器的特点(优势)
G1回收器的缺点:
G1回收器的参数设置
Bump:
单个Region使用指针碰撞的方式来放数据上面allocated是已经使用的内存空间,top就是指针的位置,unallocate是没有使用的内存空间
TLAB:
虽然存在分区Region,但是依然有线程独有的TLAB空间,这样可以保证多个线程对对象修改可以并行操作
Remebered Set
G1回收过程
8. 垃圾回收器总结
CMS是在JDK9被废弃。
/**
* -XX:+PrintCommandLineFlags
*
* -XX:+UseSerialGC:表明新生代使用Serial GC ,同时老年代使用Serial Old GC
*
* -XX:+UseParNewGC:标明新生代使用ParNew GC
*
* -XX:+UseParallelGC:表明新生代使用Parallel GC
* -XX:+UseParallelOldGC : 表明老年代使用 Parallel Old GC
* 说明:二者可以相互激活
*
* -XX:+UseConcMarkSweepGC:表明老年代使用CMS GC。同时,年轻代会触发对ParNew 的使用
* @author shkstart shkstart@126.com
* @create 2020 0:10
*/
public class GCUseTest {
public static void main(String[] args) {
ArrayList<byte[]> list = new ArrayList<>();
while(true){
byte[] arr = new byte[100];
list.add(arr);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
9. GC日志分析
下面两种是等价的
-Xms60m -Xmx60m -XX:+PrintGC
-Xms60m -Xmx60m -verbose:gc
public class GCLogTest {
public static void main(String[] args) {
ArrayList<byte[]> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
byte[] arr = new byte[1024 * 100];//100KB
list.add(arr);
}
}
[GC (Allocation Failure) 15289K->13782K(58880K), 0.0044617 secs]
[GC (Allocation Failure) 29081K->29184K(58880K), 0.0046940 secs]
[Full GC (Ergonomics) 29184K->28807K(58880K), 0.0102882 secs]
[Full GC (Ergonomics) 44125K->43710K(58880K), 0.0060180 secs]
GC、Full GC: GC的类型,GC只在新生代上进行,Full GC包括永生代,新生代,老年代。
Allocation Failure: GC发生的原因。
15289K->13782K:堆在GC前的大小和GC后的大小
58880K:总共的堆大小。
0.0044617 secs: GC持续的时间。
-Xms60m -Xmx60m -XX:+PrintGCDetails
[GC (Allocation Failure) [PSYoungGen: 15282K->2548K(17920K)] 15282K->13874K(58880K), 0.0417173 secs] [Times: user=0.00 sys=0.00, real=0.04 secs]
[GC (Allocation Failure) [PSYoungGen: 17847K->2500K(17920K)] 29173K->29028K(58880K), 0.0073599 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 2500K->0K(17920K)] [ParOldGen: 26528K->28807K(40960K)] 29028K->28807K(58880K), [Metaspace: 3495K->3495K(1056768K)], 0.0135070 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
[Full GC (Ergonomics) [PSYoungGen: 15318K->3000K(17920K)] [ParOldGen: 28807K->40709K(40960K)] 44126K->43710K(58880K), [Metaspace: 3496K->3496K(1056768K)], 0.0167859 secs] [Times: user=0.00 sys=0.02, real=0.02 secs]
Heap
PSYoungGen total 17920K, used 10253K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)
eden space 15360K, 66% used [0x00000000fec00000,0x00000000ff603510,0x00000000ffb00000)
from space 2560K, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x0000000100000000)
to space 2560K, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd80000)
ParOldGen total 40960K, used 40709K [0x00000000fc400000, 0x00000000fec00000, 0x00000000fec00000)
object space 40960K, 99% used [0x00000000fc400000,0x00000000febc17f0,0x00000000fec00000)
Metaspace used 3502K, capacity 4498K, committed 4864K, reserved 1056768K
class space used 387K, capacity 390K, committed 512K, reserved 1048576K
GC, Full GC:同样是GC的类型
Allocation Failure: GC原因
PsYoungGen:使用了Parallel Scavenge并行垃圾收集器的新生代GC前后大小的变化
ParOldGen:使用了Parallel Old并行垃圾收集器的老年代GC前后大小的变化
Metaspace:元数据区GC前后大小的变化,JDK1.8中引入了元数据区以替代永久代
secs: 指GC花费的时间
Times: user:指的是垃圾收集器花费的所有CPu时间
sys:花费在等待系统调用或系统事件的时间
real:GC从开始到结束的时间,包括其他进程占用时间片的实际时间。
-Xms60m -Xmx60m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
2022-12-16T23:07:42.172+0800: 0.260: [GC (Allocation Failure) [PSYoungGen: 15282K->2544K(17920K)] 15282K->13894K(58880K), 0.0420238 secs] [Times: user=0.00 sys=0.00, real=0.04 secs]
2022-12-16T23:07:42.213+0800: 0.270: [GC (Allocation Failure) [PSYoungGen: 17843K->2536K(17920K)] 29193K->29112K(58880K), 0.0083888 secs] [Times: user=0.01 sys=0.13, real=0.02 secs]
2022-12-16T23:07:42.229+0800: 0.278: [Full GC (Ergonomics) [PSYoungGen: 2536K->0K(17920K)] [ParOldGen: 26576K->28807K(40960K)] 29112K->28807K(58880K), [Metaspace: 3494K->3494K(1056768K)], 0.0184285 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]
2022-12-16T23:07:42.244+0800: 0.301: [Full GC (Ergonomics) [PSYoungGen: 15318K->3000K(17920K)] [ParOldGen: 28807K->40709K(40960K)] 44125K->43710K(58880K), [Metaspace: 3495K->3495K(1056768K)], 0.0148117 secs] [Times: user=0.05 sys=0.06, real=0.02 secs]
2022-12-16T23:07:42.172+0800: -XX:+PrintGCDateStamps 参数打印的,表示当前打印的时间戳
0.260:-XX:+PrintGCTimeStamps 参数打印的,表示JVM启动了多久。
GC真正耗时:real
/**
* 在jdk7 和 jdk8中分别执行
* -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
* @author shkstart shkstart@126.com
* @create 2020 0:12
*/
public class GCLogTest1 {
private static final int _1MB = 1024 * 1024;
public static void testAllocation() {
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation4 = new byte[4 * _1MB];
}
public static void main(String[] agrs) {
testAllocation();
}
}
JDK7中
JDK8中
[GC (Allocation Failure) [DefNew: 6431K->695K(9216K), 0.0084041 secs] 6431K->4791K(19456K), 0.0085389 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 7161K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 78% used [0x00000000fec00000, 0x00000000ff2506b0, 0x00000000ff400000)
from space 1024K, 67% used [0x00000000ff500000, 0x00000000ff5adf38, 0x00000000ff600000)
to space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
tenured generation total 10240K, used 4096K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 40% used [0x00000000ff600000, 0x00000000ffa00020, 0x00000000ffa00200, 0x0000000100000000)
Metaspace used 3500K, capacity 4498K, committed 4864K, reserved 1056768K
class space used 387K, capacity 390K, committed 512K, reserved 1048576K
可以看出老年代占了40%,也就是4M,相当于大对象在Eden区放不下后直接放到了老年代,但是JDK7中不是,是把Eden区中的对象升级到老年代,然后把大对象分配在Eden区
GCViewer就是一个jar包,点击就能运行,但是页面不能调节,分辨率不适配,很难用。
GCEasy
-Xms60m -Xmx60m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:./logs/gc.log
public class GCLogTest {
public static void main(String[] args) {
ArrayList<byte[]> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
byte[] arr = new byte[1024 * 100];//100KB
list.add(arr);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
./指的是当前目录,即当前工程总目录,下的logs文件夹下的gc.log,将其复制到桌面,然后上传到GCeasy分析一下。
10. 垃圾回收器的新发展
注:本文是学习 尚硅谷宋红康JVM全套教程(详解java虚拟机)所做笔记。
如何超越聪明且勤奋的人?
深思熟虑选择对的方向,早早入行,持续不断地努力。
1)选择永远比努力重要
高考分数比你低的同学去学了计算机,你分数高反而去了四大天坑两大护法中的某个专业,人家毕业月入过万,你月薪四五千。
2)早就是优势
比你早进公司的人或许能力不如你,但当你去的时候人家已经是领导了,你能力再强也是下属,也是被人领导的。论资排辈永远存在。当然,站队也比能力重要,或者说站队是一种被人忽视的实则十分重要的能力,裁员肯定先裁杂牌军,不会论你能力如何,嫡系永远最后被裁。