ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java四大引用详解:强引用、软引用、弱引用、虚引用 [打印本页]

作者: 渣渣兔    时间: 2022-9-16 17:14
标题: Java四大引用详解:强引用、软引用、弱引用、虚引用

面试官考察Java引用会问到强引用、弱引用、软引用、虚引用,具体有什么区别?本篇单独来详解 @mikechen
Java引用

从JDK 1.2版本开始,对象的引用被划分为4种级别,从而使程序能更加灵活地控制对象的生命周期,这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

强引用

强引用是最普遍的引用,一般把一个对象赋给一个引用变量,这个引用变量就是强引用。
比如:
  1. //  强引用
  2. MikeChen mikechen=new MikeChen();
复制代码
 
在一个方法的内部有一个强引用,这个引用保存在Java栈中,而真正的引用内容(MikeChen)保存在Java堆中。

如果一个对象具有强引用,垃圾回收器不会回收该对象,当内存空间不足时,JVM 宁愿抛出 OutOfMemoryError异常。
如果强引用对象不使用时,需要弱化从而使GC能够回收,如下:
  1. //帮助垃圾收集器回收此对象
  2. mikechen=null;
复制代码
 
显式地设置mikechen对象为null,或让其超出对象的生命周期范围,则GC认为该对象不存在引用,这时就可以回收这个对象,具体什么时候收集这要取决于GC算法。
举例:
  1. package com.mikechen.java.refenence;
  2. /**
  3. * 强引用举例
  4. *
  5. * @author mikechen
  6. */
  7. public class StrongRefenenceDemo {
  8.     public static void main(String[] args) {
  9.         Object o1 = new Object();
  10.         Object o2 = o1;
  11.         o1 = null;
  12.         System.gc();
  13.         System.out.println(o1);  //null
  14.         System.out.println(o2);  //java.lang.Object@2503dbd3
  15.     }
  16. }
复制代码
 
StrongRefenenceDemo 中尽管 o1已经被回收,但是 o2 强引用 o1,一直存在,所以不会被GC回收。
 
软引用

软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference 类来实现。
比如:
  1. String str=new String("abc");                                     // 强引用
  2. SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用
复制代码
 
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。
先通过一个例子来了解一下软引用:
  1. /**
  2. * 弱引用举例
  3. *
  4. * @author mikechen
  5. */
  6. Object obj = new Object();
  7. SoftReference softRef = new SoftReference<Object>(obj);//删除强引用
  8. obj = null;//调用gc
  9. // 对象依然存在
  10. System.gc();System.out.println("gc之后的值:" + softRef.get());
复制代码
 
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
  1. ReferenceQueue<Object> queue = new ReferenceQueue<>();
  2. Object obj = new Object();
  3. SoftReference softRef = new SoftReference<Object>(obj,queue);//删除强引用
  4. obj = null;//调用gc
  5. System.gc();
  6. System.out.println("gc之后的值: " + softRef.get()); // 对象依然存在
  7. //申请较大内存使内存空间使用率达到阈值,强迫gc
  8. byte[] bytes = new byte[100 * 1024 * 1024];//如果obj被回收,则软引用会进入引用队列
  9. Reference<?> reference = queue.remove();if (reference != null){
  10.     System.out.println("对象已被回收: "+ reference.get());  // 对象为null
  11. }
复制代码
 
软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收。
我们看下 Mybatis 缓存类 SoftCache 用到的软引用:
  1. public Object getObject(Object key) {
  2.     Object result = null;
  3.     SoftReference<Object> softReference = (SoftReference)this.delegate.getObject(key);
  4.     if (softReference != null) {
  5.         result = softReference.get();
  6.         if (result == null) {
  7.             this.delegate.removeObject(key);
  8.         } else {
  9.             synchronized(this.hardLinksToAvoidGarbageCollection) {
  10.                 this.hardLinksToAvoidGarbageCollection.addFirst(result);
  11.                 if (this.hardLinksToAvoidGarbageCollection.size() > this.numberOfHardLinks) {
  12.                     this.hardLinksToAvoidGarbageCollection.removeLast();
  13.                 }
  14.             }
  15.         }
  16.     }
  17.     return result;}
复制代码
 
注意:软引用对象是在jvm内存不够的时候才会被回收,我们调用System.gc()方法只是起通知作用,JVM什么时候扫描回收对象是JVM自己的状态决定的,就算扫描到软引用对象也不一定会回收它,只有内存不够的时候才会回收。
 
弱引用

弱引用的使用和软引用类似,只是关键字变成了 WeakReference:
  1. MikeChen mikechen = new MikeChen();
  2. WeakReference<MikeChen> wr = new WeakReference<MikeChen>(mikechen );
复制代码
 
弱引用的特点是不管内存是否足够,只要发生 GC,都会被回收。
举例说明:
  1. public class WeakHashMapDemo {
  2.     public static void main(String[] args) throws InterruptedException {
  3.         myHashMap();
  4.         myWeakHashMap();
  5.     }
  6.     public static void myHashMap() {
  7.         HashMap<String, String> map = new HashMap<String, String>();
  8.         String key = new String("k1");
  9.         String value = "v1";
  10.         map.put(key, value);
  11.         System.out.println(map);
  12.         key = null;
  13.         System.gc();
  14.         System.out.println(map);
  15.     }
  16.     public static void myWeakHashMap() throws InterruptedException {
  17.         WeakHashMap<String, String> map = new WeakHashMap<String, String>();
  18.         //String key = "weak";
  19.         // 刚开始写成了上边的代码
  20.         //思考一下,写成上边那样会怎么样? 那可不是引用了
  21.         String key = new String("weak");
  22.         String value = "map";
  23.         map.put(key, value);
  24.         System.out.println(map);
  25.         //去掉强引用
  26.         key = null;
  27.         System.gc();
  28.         Thread.sleep(1000);
  29.         System.out.println(map);
  30.     }}
复制代码
 
弱引用的应用
WeakHashMap
  1. public class WeakHashMapDemo {
  2.     public static void main(String[] args) throws InterruptedException {
  3.         myHashMap();
  4.         myWeakHashMap();
  5.     }
  6.     public static void myHashMap() {
  7.         HashMap<String, String> map = new HashMap<String, String>();
  8.         String key = new String("k1");
  9.         String value = "v1";
  10.         map.put(key, value);
  11.         System.out.println(map);
  12.         key = null;
  13.         System.gc();
  14.         System.out.println(map);
  15.     }
  16.     public static void myWeakHashMap() throws InterruptedException {
  17.         WeakHashMap<String, String> map = new WeakHashMap<String, String>();
  18.         //String key = "weak";
  19.         // 刚开始写成了上边的代码
  20.         //思考一下,写成上边那样会怎么样? 那可不是引用了
  21.         String key = new String("weak");
  22.         String value = "map";
  23.         map.put(key, value);
  24.         System.out.println(map);
  25.         //去掉强引用
  26.         key = null;
  27.         System.gc();
  28.         Thread.sleep(1000);
  29.         System.out.println(map);
  30.     }}
复制代码
 
当key只有弱引用时,GC发现后会自动清理键和值,作为简单的缓存表解决方案。
ThreadLocal
[code]static class ThreadLocalMap {    static class Entry extends WeakReference




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4