强应用、软引用、弱引用、虚引用 分别是什么?

image

一、强引用Reference

  当内存不足,JVM开始垃圾回收,对于强引用对象,就算出现了OOM也不会对该对象进行回收。 强引用时我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表名对象还活着,垃圾回收器不会碰着类对象。 在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用,当一个对象被强引用变量引用时,它处于可达状态,他是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收,因此强引用是造成Java内存泄漏的主要原因之一。

public class HelloGC {
    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
    }
}

二、软引用SoftReference

  软引用是相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference类来实现,可以让对象豁免一些垃圾收集。 对于软引用的对象来说:当系统内存充足时他不会被回收,当系统内存不足时,他会被回收。 软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用。

public class HelloGC {
    public static void softRef_Memory_Enough() {
        Object o = new Object();
        SoftReference<Object> softReference = new SoftReference<Object>(o);
        System.out.println(o);
        System.out.println(softReference.get());

        o = null;
        System.gc();

        System.out.println(o);
        System.out.println(softReference.get());

    }

    public static void main(String[] args) throws InterruptedException {
        softRef_Memory_Enough();
    }
}
//java.lang.Object@7cca494b
//java.lang.Object@7cca494b

//null
//java.lang.Object@7cca494b  内存够用情况下不会回收

public class HelloGC {
    public static void softRef_Memory_NotEnough() {
        Object o = new Object();
        SoftReference<Object> softReference = new SoftReference<Object>(o);
        System.out.println(o);
        System.out.println(softReference.get());

        o = null;
        System.gc();

        try {
            byte byteArray[] = new byte[10 * 1024 * 1024];
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println(o);
            System.out.println(softReference.get());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        softRef_Memory_NotEnough();
    }
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.wang.mq.activemq_springboot.HelloGC.softRef_Memory_NotEnough(HelloGC.java:35)
	at com.wang.mq.activemq_springboot.HelloGC.main(HelloGC.java:45)
//java.lang.Object@7cca494b
//java.lang.Object@7cca494b
//null
//null  内存不够用被回收

弱引用WeakReference

  弱引用需要用java.lang.ref.WeakReference类来实现,他比软引用生存周期更短; 
  不管JVM内存是否够用,只要有GC运行就会被回收

public class HelloGC {
    public static void weakReference() {
        Object o = new Object();
        WeakReference<Object> weakReference = new WeakReference<Object>(o);
        System.out.println(o);
        System.out.println(weakReference.get());

        o = null;
        System.gc();

        System.out.println(o);
        System.out.println(weakReference.get());
    }

    public static void main(String[] args) throws InterruptedException {
        weakReference();
    }
}
//java.lang.Object@7cca494b
//java.lang.Object@7cca494b
//null
//null

什么情况下用软引用

  假如有一个应用程序需要读取大量图片, 
    如果每次读取图片都从硬盘读取则会严重影响性能, 
    如果一次性全部加载到内存中又可能造成内存溢出。 
  此时可以使用软引用来解决。 
  设计思路是:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,当内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。

Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();

你知道弱引用,能谈谈WeakHashMap吗

https://blog.csdn.net/qiuhao9527/article/details/80775524

public class HelloGC() {
	public static void weakHashMap() {
        WeakHashMap map = new WeakHashMap();
        Integer key = new Integer("1");
        String value = "WeakHashMap";
        map.put(key,value);

        System.out.println(map);

        key = null;

        System.out.println(map);

        System.gc();

        System.out.println(map);
    }

    public static void main(String[] args) throws InterruptedException {
        weakHashMap();
    }
}
//{1=WeakHashMap}
//{1=WeakHashMap}
//{}

虚引用 PhantomReference

 需要用java.lang.ref.PhantomReference类来实现 
 与其他几种引用都不同,虚引用并不会决定对象的生命周期 
 如果一个对象持有虚引用,那么他就和没有任何引用一样,随时会被GC回收,也不能单独通过它来访问对象,虚引用必须和引用队列(ReferenceQueue)配合使用 
 虚引用的主要作用是跟踪对象被垃圾回收的状态。 
设置虚引用的唯一目的就是在这个对象被垃圾回收的时候收到一个系统通知或者后续添加进一步的处理。Java中允许使用finalize()【完成】方法在GC将对象从内存中清除出去之前做必要的清理工作。

引用队列: 
弱引用、软引用、虚引用 在被GC回收之前,会被放入引用队列

public class HelloGC() {
	public static void referenceQueue() {
       Object o = new Object();
       ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
       WeakReference<Object> weakReference = new WeakReference<Object>(o, >referenceQueue);
       System.out.println(o);
       System.out.println(weakReference.get());
       System.out.println(referenceQueue.poll());

       o = null;
       System.gc();

       System.out.println(o);
       System.out.println(weakReference.get());
       System.out.println(referenceQueue.poll());
   }

   public static void main(String[] args) throws InterruptedException {
       referenceQueue();
   }
}
//java.lang.Object@7cca494b
//java.lang.Object@7cca494b
//null

//null
//null
//java.lang.ref.WeakReference@7ba4f24f

public class HelloGC() {
	public static void phantomReference() {
        Object o = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomReference = new PhantomReference<Object>(o, referenceQueue);
        System.out.println(o);
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());

        o = null;
        System.gc();

        System.out.println(o);
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());
    }

    public static void main(String[] args) throws InterruptedException {
        phantomReference();
    }
}
//java.lang.Object@7cca494b
//null
//null

//null
//null
//java.lang.ref.PhantomReference@7ba4f24f

jdk中直接内存的回收就用到虚引用,由于jvm自动内存管理的范围是堆内存,而直接内存是在堆内存之外(其实是内存映射文件,自行去理解虚拟内存空间的相关概念),所以直接内存的分配和回收都是有Unsafe类去操作,java在申请一块直接内存之后,会在堆内存分配一个对象保存这个堆外内存的引用,这个对象被垃圾收集器管理,一旦这个对象被回收,相应的用户线程会收到通知并对直接内存进行清理工作。

posted @ 2019-10-15 13:12  要好好吃饭  阅读(870)  评论(0编辑  收藏  举报