面试题
请写一段程序,让其运行时的表现为触发5次ygc,然后3次fgc,然后3次ygc,然后1次fgc,请给出代码以及启动参数。从网上找到答案,决定试一下。
代码
下面程序参考代码触发JVM的Full GC和Young GC
1.程序
public class GcDemo {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
System.out.println("0.------");
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 11; i++) {
byte[] e = new byte[3 * _1MB];
list.add(e);
}
System.out.println("1.------");
}
}
2.jvm参数
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xms41m -Xmx41m -Xmn10m -XX:+UseParallelGC
3.输出日志
0.------
2019-10-23T00:21:09.011-0800: [GC (Allocation Failure) [PSYoungGen: 5575K->695K(9216K)] 5575K->3775K(41984K), 0.0126284 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2019-10-23T00:21:09.025-0800: [GC (Allocation Failure) [PSYoungGen: 7161K->608K(9216K)] 10241K->9832K(41984K), 0.0114943 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2019-10-23T00:21:09.039-0800: [GC (Allocation Failure) [PSYoungGen: 6965K->544K(9216K)] 16189K->15912K(41984K), 0.0142043 secs] [Times: user=0.00 sys=0.01, real=0.02 secs]
2019-10-23T00:21:09.054-0800: [GC (Allocation Failure) [PSYoungGen: 6829K->544K(9216K)] 22197K->22056K(41984K), 0.0085964 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2019-10-23T00:21:09.064-0800: [GC (Allocation Failure) [PSYoungGen: 6835K->592K(9216K)] 28347K->28248K(41984K), 0.0155588 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
2019-10-23T00:21:09.080-0800: [Full GC (Ergonomics) [PSYoungGen: 592K->0K(9216K)] [ParOldGen: 27656K->28155K(32768K)] 28248K->28155K(41984K), [Metaspace: 3301K->3301K(1056768K)], 0.0244979 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
1.------
Heap
PSYoungGen total 9216K, used 6460K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 78% used [0x00000007bf600000,0x00000007bfc4f138,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
ParOldGen total 32768K, used 28155K [0x00000007bd600000, 0x00000007bf600000, 0x00000007bf600000)
object space 32768K, 85% used [0x00000007bd600000,0x00000007bf17eec8,0x00000007bf600000)
Metaspace used 3305K, capacity 4556K, committed 4864K, reserved 1056768K
class space used 362K, capacity 392K, committed 512K, reserved 1048576K
4.gc日志
各类gc日志可以参考JVM各类GC日志剖析。
- Minor GC
[GC (Allocation Failure) [PSYoungGen: 5575K->695K(9216K)] 5575K->3775K(41984K), 0.0126284 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
语句 | 描述 |
---|---|
GC | 新生代GC |
5575K->695K(9216K) | 新生代总内存9216K,GC前占用5575K,GC后占用695K |
0.0126284 secs | GC花费时间 |
Times: user=0.01 sys=0.00, real=0.01 secs | 用户态占用时间,内核态占用时间,实际占用时间 |
- Full GC
Full GC (Ergonomics) [PSYoungGen: 592K->0K(9216K)] [ParOldGen: 27656K->28155K(32768K)] 28248K->28155K(41984K), [Metaspace: 3301K->3301K(1056768K)], 0.0244979 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
语句 | 描述 |
---|---|
Full GC | 针对整个堆的GC |
PSYoungGen: 592K->0K(9216K) | 新生代总内存9216K,GC前占用592K,GC后占用0K |
ParOldGen: 27656K->28155K(32768K) | 老生代总内存32768K,GC前占用27656K,GC后占用28155K |
Metaspace: 3301K->3301K(1056768K) | 元空间总内存1056768K,GC前占用3301K,GC后占用3301K |
- gc类型对应的新生代日志
gc日志参考JVM各类GC日志剖析。
字段 | 描述 | gc |
---|---|---|
DefNew | Default New Generation | Serial |
ParNew | Parallel New Generation | ParNew |
PSYoungNew | Parallel Scavenge |
5.GC算法
JVM堆内存,根据对象存活特点使用分代算法。分为新生代、老生代、MetaSpace。
新生代中对象“朝生夕死”,使用复制算法(Copying)。新生代分为Eden区、From survivor区、To survivor区。分配内存时,先使用Eden。垃圾回收时,将不可回收内存对象复制到To survivor中,大对象和存活时间长的对象复制到老生代。将Eden、From survivor中的内存全部回收。下一次垃圾回收时,将不可回收内存对象复制到From survivor中,全部回收Eden、To survivor中的内存。
老生代中对象存活时间久,使用标记压缩算法(Mark-Compact)。垃圾回收时,先标记可回收内存对象,然后将其回收,在将不可回收内存整理压缩。避免内存碎片。
判断对象是否可回收,使用可达性分析算法(Reachability-Analysis)。使用GC Roots为根节点,向下搜索。一个对象如果没有GC Roots引用他,则称该对象不可达,可回收。
6.GC触发条件
发生在新生代中的内存回收成为Minor GC。当在Eden中分配内存而Eden内存不够时会触发GC。
Full GC是针对整个堆内存进行的GC。当触发Minor GC时,新生代平均晋升到老生代的内存大小大于老生代剩余的内存大小时触发Full GC。
垃圾收集器
- 常用的垃圾收集器
常用的HotSpot垃圾收集器如下所示。
垃圾收集器.png使用命令查看jvm使用那种gc
# 命令
java -XX:+PrintCommandLineFlags -version
# 显示
-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
- 垃圾收集器指标
- 停顿时间:垃圾回收过程应用程序暂停时间。响应速度优先,要减少停顿时间。
- 吞吐量:程序运行周期中,应用程序耗时/系统运行耗时。系统运行耗时=应用程序耗时+GC耗时。吞吐量优先时,要减少GC耗时。
收集器 | 串行、并行or并发 | 新生代/老年代 | 算法 | 目标 | 适用场景 | 命令 |
---|---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的Client模式 | -XX:+UseSerialGC |
Serial Old | 串行 | 老年代 | 标记-整理 | 响应速度优先 | 单CPU环境下的Client模式、CMS的后备预案 | 上一项启动,这一项就启动 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境时在Server模式下与CMS配合 | 和CMS配合使用 |
Parallel Scavenge | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 | -XX:+UseParallelGC |
Parallel Old | 并行 | 老年代 | 标记-整理 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 | 上一条启动,自动启动该项,如果不想用可以使用-XX:-UseParallelOldGC 关闭 |
CMS | 并发 | 老年代 | 标记-清除 | 响应速度优先 | 集中在互联网站或B/S系统服务端上的Java应用 |
-XX:+UseConcMarkSweepGC 启动,新生代启动ParNew |
G1 | 并发 | both | 标记-整理+复制算法 | 响应速度优先 | 面向服务端应用,将来替换CMS | -XX:+UseG1GC |
- CMS
并发标记清除算法,参考JVM 之 ParNew 和 CMS 日志分析。
- 初始标记:标记GCRoot直接可达的老生代对象,被新生代对象引用的老生代对象。触发stop the world
- 并发标记:标记上个阶段对象可达的对象
- 并发预处理:标记新生代晋升对象,老生代新分配的对象,并发阶段被修改了的对象。使用card table标记
- 可暂停的并发预处理:
- 最终标记:重新扫描堆中的对象,进行可达性分析,标记活着的对象。触发stop the world
- 并发清除:清除垃圾对象,会产生浮动垃圾
- 重置:准备下一次收集
- G1
内存引入region,将堆内存分为2048个region。一个region可以是Eden、Survival、Old区。
引用
Java HotSpot VM Options
Java JVM 参数设置大全
JVM 系列文章之 Full GC 和 Minor GC
JVM 垃圾回收器工作原理及使用实例介绍
Major GC和Full GC的区别是什么?触发条件呢?
G1垃圾回收器调优
Java Hotspot G1 GC的一些关键技术
https://plumbr.io/handbook/what-is-garbage-collection
7种垃圾收集器
垃圾回收算法与 JVM 垃圾回收器综述
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
详解CMS垃圾回收机制
网友评论