强软弱虚四大引用
1 概述
在JVM里面把引用分成四种类型,每种类型在JVM进行垃圾回收的时候又不同的操作,这四种类型非别是:
Reference:强引用
SoftReference:软引用
WeekRerence:弱引用
PhantonReference:虚引用
2 强引用
95%的情况下我们使用过的引用都是强引用
2.1 垃圾回收方式
当JVM进行垃圾回收时,遇到强引用是不会进行回收的,哪怕是发生啦OOM异常。
强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为null,一般认为就是可以被垃圾收集的了(当然具体回收时机还是要看垃圾收集策略)。
2 .2 代码实例
3 软引用
3.1 垃圾回收方式
内存足够的情况下不收,内存不足/发生OOM会回收
3.2 代码实例
package InterviewTest;
import java.lang.ref.SoftReference;
public class SoftRefenceDemo {
/**
* 内存够用不回收
*/
public static void softRef_Memory_Enough() {
Object o1 = new Object();
SoftReference<Object> softReference = new SoftReference<Object>(o1);
System.out.println(o1);
System.err.println(softReference);
o1=null;
System.gc();
System.out.println(o1);
System.out.println(softReference.get());
}
/**
* 内存不够才回收
*/
public static void softRef_Memory_NotEnough() {
Object o1 = new Object();
SoftReference<Object> softReference = new SoftReference<Object>(o1);
System.out.println(o1);
System.err.println(softReference);
o1=null;
// System.gc();
try {
byte[] bytes = new byte[30*1024*1024];
System.out.println(bytes);
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println(o1);
System.out.println(softReference.get());
}
System.out.println("**************");
}
public static void main(String[] args) {
// softRef_Memory_Enough();
softRef_Memory_NotEnough();
}
}
4 弱引用
4.1 垃圾回收方式
不论内存是否足够,只要发生GC回收,都会被回收
4.2 代码实例
package InterviewTest;
import java.lang.ref.WeakReference;
public class WeakRefenceDemo {
public static void main(String[] args) {
Object o1 = new Object();
WeakReference<Object> weakReference = new WeakReference<Object>(o1);
System.out.println("o1:"+o1);
o1 = null;
System.out.println("o1:"+o1);
System.out.println("weakReference:"+weakReference.get());
System.gc();
System.out.println("*******************");
System.out.println("o1:"+o1);
System.out.println("weakReference:"+weakReference.get());
}
}
4.3 使用场景
安卓手机,前端浏览器
保证不用每次都从硬盘读取,但又要防止OOM异常
4.4 WeakHashMap
当一个key已经无效(key=null)的时候,只要发生GC,
这个键值对就会被回收,map中其他的key有效的不会被回收。
4.4.1 代码示例
package InterviewTest;
import java.util.HashMap;
import java.util.WeakHashMap;
public class WakHashMapDemo {
public static void main(String[] args) {
myHashMap();
System.out.println("-----------------------------------");
myWeakHashMap();
}
public static void myHashMap() {
HashMap<Integer, String> map = new HashMap<>();
Integer key = new Integer(1);
String value = "HashMap";
map.put(key, value);
System.out.println(map);
System.out.println(" ******* ");
key = null;
System.out.println(map);
System.out.println(" ******* ");
System.gc();
System.out.println("map:"+map+" size:"+map.size());
}
public static void myWeakHashMap() {
WeakHashMap<Integer, String> map = new WeakHashMap<>();
Integer key = new Integer(2);
String value = "HashMap";
map.put(key, value);
Integer key2 = new Integer(22);
String value2 = "HashMap2";
map.put(key2, value2);
System.out.println(map);
System.out.println(" ******* ");
key = null;
System.out.println(map);
System.out.println(" ******* ");
System.gc();
System.out.println("map:"+map+" size:"+map.size());
}
}
5 虚引用
5.1 回收方式
虚引用,形同虚设,不会决定对象的生命周期。
一个对象持有虚引用,那它就跟没有任何引用一样,在任何时候都能被垃圾回收器回收。他不能单独使用,也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。
虚引用的作用是跟踪对象被垃圾回收的状态,仅仅是提供一种确保对象被finalize以后,做某些事情的机制。
虚引用对象的get()方法返回值总是null
5.2 代码实例
package InterviewTest;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
/**
* @author admin
*java 提供了4种引用类型,在垃圾回收的时候,都有自己各自的特点
*ReferenceQueue是用来配额引用工作的,没有ReferenceQueue一样可以运行
*
*创建引用的时候可以指定关联的队列,当GC释放对象内存的时候,会将引用加入到引用队列
*如果程序发现了某个虚引用已经加入到引用队列, 那么就可以在引用的对象内存被回收之前采取必要的行动
*这相当于是一种通知机制
*
*当关联的引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。
*通过这种方式,JVM允许我们在对象被销毁后,做一些我们自己想做 的事情。
*
*
*/
public class PhantomReferenceDemo {
public static void main(String[] args) throws InterruptedException {
Object o1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference< Object> phantomReference = new PhantomReference<Object>(o1, referenceQueue);
System.out.println("o1:"+o1);
System.out.println("phantomReference:"+phantomReference.get());
System.out.println("referenceQueue:"+referenceQueue.poll());
System.out.println("****************");
o1=null;
System.gc();
Thread.sleep(500);
System.out.println("****************");
System.out.println("o1:"+o1);
System.out.println("phantomReference:"+phantomReference.get());
System.out.println("第一次referenceQueue:"+referenceQueue.poll());
System.out.println("第二次referenceQueue:"+referenceQueue.poll());
}
}
5.3 引用队列
在对象被回收之前,可以放到引用队列里面,那么GC之后输出该对象,为null,但是输出引用队列的话,值为该对象,但是再输出一次的话就为null了。
可以在对象被回收之前在做一些事情。(“类似于“死缓” ”)
5.3 .1 引用队列代码实例
package InterviewTest;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class ReferenceQueueDemo {
public static void main(String[] args) throws Exception {
Object o1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
WeakReference<Object> weakReference = new WeakReference<Object>(o1,referenceQueue);
System.out.println(o1);
System.out.println(weakReference.get());
System.out.println(referenceQueue.poll());
System.out.println("**************");
o1=null;
System.gc();
Thread.sleep(500);
System.out.println(o1);
System.out.println(weakReference.get());
System.out.println(referenceQueue.poll());
System.out.println("-----");
System.out.println(referenceQueue.poll());
}
}