日常记录——JVM—java的四种引用及代码演示效果

一、简介

java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象,对象的引用包括:
1.强引用:使用 new 这个关键字创建对象时创建出来的对象就是强引用。GC宁愿抛出OutOfMemoryError也不会回收有强引用的对象。
2.软引用SoftReference:软引用的对象如果内存空间足够,GC不会回收,如果内存空间不足,就会回收该对象。可以和引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被回收,就会把这个软引用加入到与之关联的引用队列中。软引用可用来实现内存敏感的缓存。
3.弱引用WeakReference:弱引用的对象拥有更短暂的生命周期,只要GC工作,发现就回收,也可和引用队列联合使用。ThreadLocal的内部类ThreadLocalMap的静态内部类Entry继承了WeakReference。
4.虚引用PhantomReference:在任何时候都可能被垃圾回收,必须和引用队列联合使用,并且通过get()方法获取不到引用对象。被用来做堆外内存的监控(Netty)。

二、代码演示效果

1.强引用

public class StrongReference {
    public static void main(String[] args) {
        ReferenceTest o = new ReferenceTest();
        //引用指向null  将这行注释掉  执行结果不打印"我被回收了"
        o = null;
        //回收
        System.gc();
        //主线程一直睡
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class ReferenceTest {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("我被回收了");
    }
}

2.软引用

public class SoftReferenceTest {

    public static void main(String[] args) {
        //一个大小为10M的软引用数组
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024*1024*10]);
        System.out.println(softReference.get());
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(softReference.get());
        //创建大小为15M 的字节数组
        byte[] bytes = new byte[1024*1024*15];
        //设置内存大小为20M  所以  软引用会被回收  返回null
        System.out.println(softReference.get());
    }
}

设置运行内存为20M:
日常记录——JVM—java的四种引用及代码演示效果_第1张图片
执行结果:
日常记录——JVM—java的四种引用及代码演示效果_第2张图片
3.弱引用

public class WeakReferenceTest {
    public static void main(String[] args) {
        WeakReference<ReferenceTest> weakReference = new WeakReference(new ReferenceTest());
        System.out.println(weakReference.get());
        System.gc();
        System.out.println(weakReference.get());
    }
}

效果:
日常记录——JVM—java的四种引用及代码演示效果_第3张图片
4.虚引用:

public static void main(String[] args) {
        //填冲内存  触发GC
        List<byte[]> bytes = new ArrayList<>();
        //引用队列
        ReferenceQueue<ReferenceTest> queue = new ReferenceQueue<>();
        //虚引用
        PhantomReference<ReferenceTest> phantomReference = new PhantomReference<>(new ReferenceTest(), queue);

        System.out.println(phantomReference.get());

        new Thread(() -> {
            while (true){
                bytes.add(new byte[1024*1024*1]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(phantomReference.get());
            }
        }).start();

        new Thread(() -> {
            while (true){
                Reference<? extends ReferenceTest> poll = queue.poll();
                if (null != poll){
                    System.out.println("虚引用对象被回收了" + poll);
                }
            }
        }).start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

内存设置:
日常记录——JVM—java的四种引用及代码演示效果_第4张图片
效果图:
日常记录——JVM—java的四种引用及代码演示效果_第5张图片
注意:Java中提供这四种引用类型主要有两个目的:

  1. 是可以让程序员通过代码的方式决定某些对象的生命周期。
  2. 是有利于JVM进行垃圾回收。

你可能感兴趣的:(JVM,jvm,java,队列,后端)