JVM学习笔记(13) 垃圾回收-相关概念

一.System.gc() 的理解

在这里插入图片描述

public class SystemGCTest {
    public static void main(String[] args) {
        new SystemGCTest();
        //  就是调了这个 Runtime.getRuntime().gc();
        System.gc(); // 提醒jvm的垃圾回收器执行gc, 但是不确定是否马上执行gc

        // 强制调用使用引用的对象的finalize()方法
        // System.runFinalization();
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("重写了finalize().....");
    }
}

代码示例

/**
 * -XX:+PrintGCDetails
 */
public class LocalVarGC {
    public void localvarGC1() {
        byte[] buffer = new byte[10 * 1024 * 1024];
        System.gc();
    }

    public void localvarGC2() {
        byte[] buffer = new byte[10 * 1024 * 1024];
        buffer = null;
        System.gc();
    }

    public void localvarGC3() {
        {
            byte[] buffer = new byte[10 * 1024 * 1024];
        }
        System.gc();
    }

    public void localvarGC4() {
        {
            byte[] buffer = new byte[10 * 1024 * 1024];
        }
        int value = 10;
        System.gc();
    }

    public void localvarGC5() {
        localvarGC1();
        System.gc();
    }

    public static void main(String[] args) {
        LocalVarGC local = new LocalVarGC();
        local.localvarGC1();
    }
}

GC1

在这里插入图片描述

GC2

在这里插入图片描述

GC3

在这里插入图片描述

GC4

在这里插入图片描述

GC5

在这里插入图片描述


二.内存溢出与内存泄漏

内存溢出(OOM)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

内存泄漏(Memory Leak)

在这里插入图片描述

如下图右边有个应该断开的引用没有断开,就导致了内存的泄漏
在这里插入图片描述

举例

例子1: 比如Runtime对象,声明周期一直存在
在这里插入图片描述


三.Stop The World

在这里插入图片描述
在这里插入图片描述

public class StopTheWorldDemo {

    public static class WorkThread extends Thread {
        List<byte[]> list = new ArrayList<>();

        @Override
        public void run() {
            try {

                while (true) {
                    for (int i = 0; i < 1000; i++) {
                        byte[] buffer = new byte[1024];
                        list.add(buffer);
                    }

                    if (list.size() > 10000) {
                        list.clear();
                        System.gc(); // 会触发full GC, 进而会出现STW事件
                    }
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static class PrintThread extends Thread {
        public final long startTime = System.currentTimeMillis();

        @Override
        public void run() {
            try {
                while (true) {
                    long end = System.currentTimeMillis() - startTime;
                    System.out.println(end / 1000 + "." + end % 1000);
                    Thread.sleep(1000);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        WorkThread w = new WorkThread();
        PrintThread p = new PrintThread();
        w.start();
        p.start();
    }
}

四.垃圾回收的并行与并发

并发(Concurrent)

在这里插入图片描述

并行(Parallel)

在这里插入图片描述
在这里插入图片描述

垃圾回收的并发与并行

在这里插入图片描述
在这里插入图片描述


五.安全点与安全区域

安全点(Safepoint)

在这里插入图片描述
在这里插入图片描述

安全区域(Safe Region)

在这里插入图片描述
在这里插入图片描述


六.再谈引用: 强引用

在这里插入图片描述
在这里插入图片描述

强引用(Strong Reference) – 不回收

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


七.再谈引用: 软引用(Soft Reference) – 内存不足即回收

在这里插入图片描述
在这里插入图片描述

/**
 * -Xms10m -Xmx10m -XX:+PrintGCDetails
 */
public class SoftReferenceTest {
    public static  class  User {
        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public int id;
        public String name;

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) {
        // 创建对象, 建立软引用
        SoftReference<User> us = new SoftReference<>(new User(1, "胡琦"));

/*      这段代码和上面的一句的作用是有一样的
        User huqi = new User(1, "huqi");
        SoftReference<User> userSoftReference = new SoftReference<>(huqi);
        huqi = null;*/


        // 从软引用中重新获得强引用对象
        System.out.println(us.get());

        System.gc();
        System.out.println("After GC : ");
        // 垃圾回收之后获得软引用中的对象
        System.out.println(us.get()); // 由于堆内存空间足够, 所以不会回收软引用的可达对象

        try {
            // 让系统以为内存资源紧张
            byte[] b = new byte[1024 * 1024 * 7];
        }catch (Throwable throwable) {
            throwable.printStackTrace();
        }finally {
            // 再次从软引用中获取数据
            System.out.println(us.get());// 在报OOM之前, 垃圾回收器会回收软引用的可达对象
        }
    }

}

在这里插入图片描述


八.再谈引用: 弱引用(Weak Reference) – 发现即回收

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关于weakHashMap可参考 https://blog.csdn.net/u013467442/article/details/105826778


九.再谈引用: 虚引用(Phantom Reference) – 对象回收跟踪

在这里插入图片描述
在这里插入图片描述

public class PhantomReferenceTest {
    /**
     * 当前类对象的声明
     */
    public static PhantomReferenceTest obj;

    /**
     * 引用队列
     */
    static ReferenceQueue<PhantomReferenceTest> phantomQueue = null;

    public static class CheckRefQueue extends Thread {
        @Override
        public void run() {
            while (true) {
                // 当GC回收的时候将虚引用对象放入队列中的时候,会进入循环对队列进行操作
                if (phantomQueue != null) {
                    PhantomReference<PhantomReferenceTest> objt = null;
                    try {
                        // 将队列中的元素取出来
                        objt = (PhantomReference<PhantomReferenceTest>) phantomQueue.remove();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 判断取出的元素,如果不为空就进行记录
                    if (objt != null) {
                        System.out.println("追踪垃圾回收过程: PhantomReferenceTest实例被GC了 -> " +
                                JSON.toJSONString(objt));
                    }
                }
            }
        }
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("调用当前类的finalize()方法");
        // 让当前对象复活
        obj = this;
    }

    public static void main(String[] args) {
        Thread t = new CheckRefQueue();
        // 设置为守护线程, 当程序中没有非守护线程时, 守护线程才会结束
        t.setDaemon(true);
        t.start();

        phantomQueue = new ReferenceQueue<>();
        obj = new PhantomReferenceTest();
        // 构造了 PhantomReferenceTest 对象的虚引用, 并指定了引用队列
        PhantomReference<PhantomReferenceTest> phantomReference = new PhantomReference<>(obj, phantomQueue);

        try {
            // 不可获取虚引用中的对象
            System.out.println(phantomReference.get());

            // 将强引用去除
            obj = null;
            // 第一次进行GC, 由于对象可复活, GC无法回收该对象
            System.gc();
            Thread.sleep(1000);

            if (obj == null) {
                System.out.println("obj 是 null");
            } else {
                System.out.println("obj 可用");
            }
            System.out.println("第二次gc");

            obj = null;
            // 一旦将obj对象回收, 就会将次虚引用存放到引用队列中
            System.gc();
            Thread.sleep(1000);

            if (obj == null) {
                System.out.println("obj 是 null");
            } else {
                System.out.println("obj 可用");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述


十.再谈引用: 终结器引用(Final reference)

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值