【JVM学习笔记】二、JVM 中的垃圾回收

关于JVM 的学习笔记,再更新一下~

这一篇主要记录JVM 中的垃圾回收的相关内容

一、HotSpot 的Java 堆为什么要分为新生代和老年代?常见的堆内存分配策略是什么?

对象优先分配在Eden区,大对象直接进入老年代,长期存活(老年代动态年龄阈值)的对象将进入老年代

为了更好地回收内存,更快地分配内存

  • -Xms 最小堆内存;-Xmx 最大堆内存;-Xmn 设置新生代内存大小

二、HotSpot的GC的分类(面向的区域)?

部分收集(Partial GC) + 整堆收集(Full GC)

  • 部分收集
  1. 新生代收集(Minor GC/ Young GC)

  2. 老年代收集(Major GC/ Old GC)

  3. 混合收集(Fixed GC):对整个新生代和部分老年代进行GC

  • 整堆收集:收集整个Java 堆 和 方法区

三、空间分配担保机制是什么?

JDK1.6之前, Minor GC 前,如果老年代最大可用的连续空间大于新生代所有对象总空间,那这一次 Minor GC 可以确保是安全的。如果不成立,则JVM先查看参数值-XX:HandlePromotionFailure是否允许担保失败。若允许,那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次 Minor GC(有风险的);如果小于或不允许担保失败,则改为进行一次 Full GC

JDK 1.6之后老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行 Minor GC,否则将进行 Full GC

  • 空间分配担保是为了确保在 Minor GC 之前老年代本身还有容纳新生代所有对象的剩余空间

四、如何判断一个对象已经无效?

引用计数法/ 可达性分析

  • 引用计数法
  1. 对象中添加一个引用计数器,有一个地方引用它则+1,引用失效-1。计数为0的对象已经无效

  2. 简单高效。但是目前主流JVM 没有用它,因为存在循环引用的问题

  • 可达性分析
  1. GC Roots 作为起点,该节点向下搜索的路径被称为“引用链”,当一个对象到GC root 没有任何引用链时,则该对象已无效

  2. 可作为GC Roots 的对象:虚拟机栈(本地变量表)、本地方法栈(Native 方法)中引用的对象、方法去中类静态属性及常量引用的对象、所有被同步锁持有的对象

  3. 不可达对象并非一定会被GC,至少要经过两次标记

五、如何判断一个常量是废弃常量?

该常量没有被引用了,例如在字符串常量池中存在”abc”,如果当前没有任何String对象引用它的话,就说明常量”abc”已经废弃,GC时有可能被清理出常量池

六、如何判断一个类是无用的类?

符合3个条件的类:

  1. 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何对象实例
  2. 加载该类的ClassLoader已被回收
  3. 该类对应的Class 对象没有在任何地方被引用(无法在任何地方通过反射访问该类的方法)

七、介绍强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)

  1. 强引用:“必需生活用品” 不会被GC
  2. 软引用:“可有可无的生活用品” 内存不足时才会被GC,可以实现内存敏感的高速缓存(软引用可以加速 JVM 对垃圾内存的回收速度,可以维护系统的运行安全,防止OOM
  3. 弱引用:“可有可无的生活用品”生命周期比软引用更短,垃圾回收器线程(优先级很低,不一定很快发现)扫描到即回收
  4. 虚引用:“形同虚设的生活用品” 虚引用不决定对象的生命周期,任何时候都可能被垃圾回收,主要用于跟踪对象被垃圾回收的活动必须和引用队列联合使用

八、垃圾收集有哪些算法,各自的特点?

标记-清除算法、标记-复制算法、标记-整理算法、分代收集算法

  1. 标记-清除算法:先标记,再统一回收。问题是:效率问题及会产生内存碎片
  2. 标记-复制算法:内存分为相同的两块,每次使用一块,使用完后存活对象统一复制到另外一半。问题是:存活率高时效率低,一定的空间浪费
  3. 标记-整理算法:先标记,所有存活对象向一端移动,直接清理掉端边界外的内存。问题是:效率
  4. 分代收集算法:
  • 总结上述三种算法,让他们用在合适的区域:
  1. 效率(仅基于时间复杂度):清除 > 整理 > 复制

  2. 内存整齐度:整理 = 复制 > 清除

  3. 内存利用率:整理 = 清除 > 复制

  • 新生代中对象存活率低,选择标记-复制

  • 老年代中存活率高,没有额外的空间用于分配担保,选择标记-整理,或者标记-清除

九、常见的垃圾回收器有哪些?

  • Serial 收集器:最基础,单线程(工作时暂停所有线程),简单高效。新生代采用标记-复制算法,老年代采用标记-整理算法
  • ParNew 收集器:Serial 的多线程版本

  • Parallel Scavenge 收集器:JDK1.8的默认,关注吞吐量(高效利用CPU),即CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值

  • CMS收集器(Concurrent Mark Sweep):HotSpot 第一个真正意义的并发收集器,第一次实现垃圾收集线程和用户线程基本上同时工作,关注用户线程停顿时间,使用标记清除算法
  1. 运作流程:初始标记 - 并发标记 - 重新标记 - 并发清除

  2. 优点:并发收集、低停顿

  3. 缺点:对CPU资源敏感,无法处理浮动垃圾、会产生大量空间碎片

  • G1 收集器:面向多处理器大内存的机器,既满足低停顿时间,还保证CPU高吞吐
  1. 运作流程:初始标记 - 并发标记- 最终标记 - 筛选回收,后台维护一个优先列表,根据允许的收集时间优先回收价值最大的内存区域

  2. 特点:并行+并发,分代收集,空间整合、时间停顿可预测(用户可指定)

  3. 主要是标记-整理,少数标记-复制

  • ZGC 收集器:新一代的GC收集器(JDK11),几乎所有阶段并发,不分代(Z就是个名字,没有含义哈哈哈)
------ 本文结束,感谢观看! ------
 wechat
扫一扫,访问本站