JVM(HotSpot):GC之垃圾标记阶段

文章目录

前言

我们从日常生活中应该知道,当我们去打扫一间屋子时,首先,你要判断那些事垃圾,然后,对其进行清除打扫。不然,把重要物品也给清除了,不是亏大了。

JVM垃圾回收器,也是这么工作的。

你可以把GC看作JVM这个屋子的清洁员。

那么,在打扫之前,需要精确的标记出哪些对象是垃圾对象,从而,为清理阶段做准备。

一、标记阶段算法

1、引用计数法

定义:一个对象,如果被引用了,那么,它就不能标记为垃圾,不能回收。

缺点 :存在内存泄漏问题。

当两个垃圾对象互相引用时,无法回收。

2、可达性分析算法(JVM使用)

定义 :对象直接或间接的被GC Root对象引用。则不能标记为垃圾。

哪些是GC Root对象

一般地

​ a、虚拟机栈中引用的对象

​ b、本地方法栈中引用的对象

​ c、方法区中静态变量引用的对象

​ d、字符串常量池中引用的对象

​ e、被sync锁把持的对象

​ f、局部回收和分代收集时候,产生的临时性GC Roots

二、4种引用

为什么要学习5中引用?

这个是在特定情况下,符合可达性分析算法时,依然要被回收的对象。

其中,软引用,弱引用,虚引用,终结器引用,它们也是对象,也占用着内存空间。

这几种引用,一般要结合引用队列进行回收处理。

终结器引用,无需手动编码。了解即可。

1、 强引用

​ 就是new出来的对象,即使内存不够了,也不能回收,会导致OOM

2、软引用(SoftReference)

​ 缓存技术常使用,内存不够了,才会回收相应的对象,它可以获取对象实例的方法和属性

可以配合引用队列来释放软引用自身

3、弱引用(WeakHashMap)

​ 内存够的情况下,只要GC发现,就会回收,它可以获取对象实例的方法和属性

可以配合引用队列来释放软引用自身

4、虚引用(PhantomReference)

​ 内存足够的情况下,只要GC就会被回收,无法获取对象实例的方法和属性,在于跟踪垃圾回收的过程

必须配合引用队列来释放软引用自身

三、代码案例

1、 强引用

运行参数设置

JVM内存大小设置为20M

bash 复制代码
-Xmx20m
java 复制代码
    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();
    }

运行结果

2、软引用(SoftReference)

运行参数设置

JVM内存大小设置为20M,打印GC回收信息

bash 复制代码
-Xmx20m -XX:+PrintGCDetails -verbose:gc

大致引用关系: list --> SoftReference --> byte[]

java 复制代码
    public static void soft() {
        List<SoftReference<byte[]>> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());

        }
        System.out.println("循环结束:" + list.size());
        for (SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }

运行结果:没有发生OOM错误,触发了Full GC


使用引用队列,回收软引用

java 复制代码
public class Demo2_4 {
    private static final int _4MB = 4 * 1024 * 1024;

    public static void main(String[] args) {
        List<SoftReference<byte[]>> list = new ArrayList<>();

        // 引用队列
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        for (int i = 0; i < 5; i++) {
            // 关联了引用队列, 当软引用所关联的 byte[]被回收时,软引用自己会加入到 queue 中去
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }

        // 从队列中获取无用的 软引用对象,并移除
        Reference<? extends byte[]> poll = queue.poll();
        while( poll != null) {
            list.remove(poll);
            poll = queue.poll();
        }

        System.out.println("===========================");
        for (SoftReference<byte[]> reference : list) {
            System.out.println(reference.get());
        }

    }
}

运行结果:软引用被GC回收了。

3、弱引用(WeakHashMap)

运行参数设置

JVM内存大小设置为20M,打印GC回收信息

bash 复制代码
-Xmx20m -XX:+PrintGCDetails -verbose:gc
java 复制代码
public class Demo2_5 {
    private static final int _4MB = 4 * 1024 * 1024;

    public static void main(String[] args) {
        //  list --> WeakReference --> byte[]
        List<WeakReference<byte[]>> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);
            list.add(ref);
            for (WeakReference<byte[]> w : list) {
                System.out.print(w.get()+" ");
            }
            System.out.println();

        }
        System.out.println("循环结束:" + list.size());
    }
}

运行结果

相关推荐
Algorithm157610 小时前
JVM是什么,与Java的关系是什么,以及JVM怎么实现的跨平台性
java·开发语言·jvm
王佑辉10 小时前
【jvm】所有的线程都共享堆吗
jvm
琪露诺大湿15 小时前
JavaEE-多线程初阶(1)
java·linux·开发语言·jvm·数据库·java-ee·1024程序员节
威哥爱编程17 小时前
Java Z 垃圾收集器如何彻底改变内存管理
java·jvm·zgc
与海boy20 小时前
第七章 JVM对高效并发的支持
jvm
王佑辉20 小时前
【jvm】如何设置堆内存大小
jvm
MegaDataFlowers1 天前
JDK、JRE、JVM之间的关系
java·开发语言·jvm
程序员阿鹏1 天前
详解:单例模式中的饿汉式和懒汉式
java·开发语言·jvm·后端·单例模式·eclipse
梦城忆1 天前
JVM基础(内存结构)
开发语言·jvm·python
AGi_1 天前
Java基础-JVM
java·开发语言·jvm