美文网首页
2018-07-26 java 四种引用:强引用、软引用、弱引用

2018-07-26 java 四种引用:强引用、软引用、弱引用

作者: _你好_ | 来源:发表于2018-07-26 21:33 被阅读0次

    四种引用

    1. 强引用 (Strong Reference)
    2. 软引用 (Soft Reference)
    3. 弱引用 (Weak Reference)
    4. 虚引用 (Phantom Reference)
      以上引用强度依次变弱,从引用对象到gc root 节点的一条链路上引用强度以最弱的为准,多条链路的引用强度以最强的为准
    1. 强引用 (Strong Reference)
    Test test = new Test();
    

    2. 软引用(Soft Reference)

    特点:使用软引用包裹的对象,如果该对象的引用强度为软引用则会发生gc且内存不足时被回收

        @Test
        public void softReference() {
            byte[] bytes1 = new byte[1024 * 1024 * 128];
            SoftReference<byte[]> weakReference = new SoftReference<>(bytes1);
    
            assertSame(bytes1, weakReference.get());
            bytes1 = null;
            System.out.println("before gc");
            byte[] bytes2 = new byte[1024 * 1024 * 128];
            System.out.println("after gc");
            // 如果gc时内存不足
            assertNull(weakReference.get());
        }
    

    增加启动参数

    -Xmx256m -Xmn256m -XX:+PrintGCDetails  -XX:+PrintGCDateStamps 
    
    企业微信截图_15326105016656.png

    3 弱引用 (Weak Reference)

    特点:使用弱引用包裹的对象,如果该对象的引用强度为弱引用则会在发生gc被回收

        @Test
        public void weakReference() {
            Object referent = new Object();
            WeakReference<Object> weakReference = new WeakReference<Object>(referent);
            assertSame(referent, weakReference.get());
    
            referent = null;
            System.gc();
            // 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收
            assertNull(weakReference.get());
        }
    

    虚应用 (Phantom Reference)

    虚引用是最有意思的一个
    其无论在任何适合 调用 get 方法获取到的对象都是 null
    他不像软引用、弱引用会自动回收内存,虚引用的存在更倾向于发送通知,虚引用被确定可以回收时将自己放入到 Reference 的 pending list 中。
    次数 ReferenceHandler 线程发现 pending list 中存在对象,则执行该对象的清理方法。等到下次gc时将该对象移除。

    以下代码为网上获取到的

    public static void main(String[] args) throws Exception {
            ReferenceQueue<Test> queue = new ReferenceQueue<>();
            Thread moniterThread = new Thread(() -> {
                // 监视线程,随时检查引用队列,一旦发现引用就会打印出来
                for (; ; ) {
                    Reference<? extends Test> ref = queue.poll();
                    if (ref != null) {
                        System.out.printf("%s加入引用队列%n", ref.getClass().getSimpleName());
                    }
                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
            });
            moniterThread.start();
            Test test = new Test();
            WeakReference<Test> weakReference = new WeakReference<Test>(test, queue);
            PhantomReference<Test> phantomReference = new PhantomReference<Test>(test, queue);
            // 去除强引用
            test = null;
            System.out.println(">> 第一次gc <<");
            System.gc();
            // 这里等待一段时间,保证引用进入队列,和finalize()方法执行
            Thread.sleep(100);
            System.out.println("\n>> 第二次gc <<");
            System.gc();
            assert weakReference != null && phantomReference != null;
            moniterThread.interrupt();
        }
    
        public static class Test {
            @Override
            protected void finalize() throws Throwable {
                System.out.println("== finalize() ==");
            }
        }
    

    程序执行情况如下


    企业微信截图_1532611346661.png

    该博客该出的解释为

    1532611446(1).png

    那么this逃逸呢?

    public class PhantomReferenceSaveOneselfTest {
        static volatile Test test = new Test();
    
        public static void main(String[] args) throws Exception {
            ReferenceQueue<Test> queue = new ReferenceQueue<>();
            Thread monitorThread = new Thread(() -> {
                // 监视线程,随时检查引用队列,一旦发现引用就会打印出来
                for (; ; ) {
                    Reference<? extends Test> ref = queue.poll();
                    if (ref != null) {
                        System.out.printf("%s 加入引用队列%n", ref.getClass().getSimpleName());
                    }
                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
            });
            monitorThread.start();
            PhantomReference<Test> phantomReference = new PhantomReference<Test>(test, queue);
            // 去除强引用
            test = null;
            System.out.println(">> 第一次gc <<");
            System.gc();
            // 这里等待一段时间,保证引用进入队列,和finalize()方法执行
            Thread.sleep(100);
            System.out.println("\n>> 第二次gc <<");
            System.gc();
    
            Thread.sleep(100);
            test = null;
            System.out.println("\n>> 第三次gc <<");
            System.gc();
    
            Thread.sleep(100);
            assert phantomReference != null;
            monitorThread.interrupt();
        }
    
        public static class Test {
            private byte[] bytes = new byte[1024 * 1024 * 2];
            @Override
            protected void finalize() throws Throwable {
                System.out.println("== finalize() ==");
                test = this;
            }
        }
    }
    
    企业微信截图_15326119672211.png

    相关文章

      网友评论

          本文标题:2018-07-26 java 四种引用:强引用、软引用、弱引用

          本文链接:https://www.haomeiwen.com/subject/pmlimftx.html