JVM学习笔记——垃圾回收篇

JVM学习笔记——垃圾回收篇在本系列内容中我们会对JVM做一个系统的学习 , 本片将会介绍JVM的垃圾回收部分
我们会分为以下几部分进行介绍:

  • 判断垃圾回收对象
  • 垃圾回收算法
  • 分代垃圾回收
  • 垃圾回收器
  • 垃圾回收调优
判断垃圾回收对象本小节将会介绍如何判断垃圾回收对象
引用计数法首先我们先来介绍引用计数法的定义:
  • 我们为对象附上一个当前使用量
  • 当有线程使用时,我们将该值加一;当线程停止使用时,我们将该值减一
  • 当当前使用量大于零时,我们创建该对象;当当前使用量减少为零时,我们将该对象当作垃圾回收对象
但该方法存在一个致命问题:
  • 当两个对象互相调用对方时,就会导致当前使用量一直不为空,占用内存
可达性分析算法同样我们先来简单介绍可达性分析算法:
  • 我们首先判定一些对象为Root对象
  • 我们根据这些对象来选择判定其他对象是否为垃圾回收对象
  • 当该对象直接或间接被Root对象所引用时,我们不设置为垃圾回收对象;当没有被Root对象连接时 , 设置为垃圾回收对象
然后我们来简单介绍一下Root对象的分类(来自MAT工具统计):
  • System Class:直属于Java包下的相关类,包括有Object,String,Stream,Buffer等
  • Native Stack:直属于操作系统交互的类,包括有wait等
  • Busy Monitor:读锁机制相关的类,当前状态下被锁定的对象是无法当作垃圾回收对象的
  • Thread:互动线程,线程相关的类也无法当作垃圾回收对象
可达性分析算法就是目前Java虚拟机所使用的垃圾回收器判定方法
五种引用下面我们将会介绍JVM中常用的五种引用方法,他们分别对应着不同的回收对象判定情况:
JVM学习笔记——垃圾回收篇

文章插图
我们下面来一一介绍
强引用上述图片中的A1对象就是强引用示例
我们下面介绍强引用的概念:
  • 强引用就是由Root对象直接引用的对象
然后我们介绍强引用的回收概念:
  • 只有当所有强引用连接都消失时,该对象才会被列为垃圾回收对象
  • 例如上图 , A1对象由B,C两个对象所强引用连接,只有当两个对象都取消引用后 , A1对象才会被列入回收对象
软引用上述图片中的A2对象就是软引用示例
我们下面介绍软引用的概念:
  • 软引用不是由根Root直接引用,而是采用一个软引用对象SoftReference连接
然后我们介绍软引用的回收概念:
  • 当该对象没有被强引用连接,被软引用连接时有可能会被回收
  • 每次发生垃圾回收 , 如果垃圾回收后的内存够用 , 则不进行软引用对象的垃圾回收;若内存不足,则进行软引用对象的垃圾回收
此外我们的软引用对象也是会占用内存的,所以我们也需要采用其他方法将软引用对象回收:
  • 我们通常将软引用对象绑定一个引用队列
  • 当该软引用对象不再连接任何对象时,将其放入引用队列 , 引用队列会进行检测,检测到软引用对象就会对其进行垃圾回收
我们首先给出软引用对象的相关测试代码:
package cn.itcast.jvm.t2;import java.io.IOException;import java.lang.ref.SoftReference;import java.util.ArrayList;import java.util.List;/** * 演示软引用 * -Xmx20m -XX:+PrintGCDetails -verbose:gc */public class Demo2_3 {private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) throws IOException {// 这部分是强引用对象,我们会发现所有内存都放在内部 , 导致内存不足List<byte[]> list = new ArrayList<>();for (int i = 0; i < 5; i++) {list.add(new byte[_4MB]);}System.in.read();// 调用下列方法(软引用)soft();}// 软引用public static void soft() {// 软引用逻辑:list --> SoftReference --> byte[]// 创建软引用List<SoftReference<byte[]>> list = new ArrayList<>();for (int i = 0; i < 5; i++) {// 首先new一个SoftReference并赋值SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);System.out.println(ref.get());// 将SoftReference加入listlist.add(ref);System.out.println(list.size());}System.out.println("循环结束:" + list.size());for (SoftReference<byte[]> ref : list) {System.out.println(ref.get());}}}/*调试过程:如果我们采用强引用方法,正常情况下会在第五次循环时报错但是如果我们采用软引用,我们会在第五次循环时发生gc清理,这时我们前四次的添加(list的前四位)就会被软引用清除所以我们在最后循环结束后查看数组会发现:nullnullnullnull[B@330bedb4*/

推荐阅读