JVM学习(五)对象的引用类型
一、引言
前面我们学习了JVM的垃圾回收机制,我们知道了垃圾回收是JVM的自发行为;虽然我们可以通过System.gc() 或Runtime.getRuntime().gc()进行显式调用垃圾回收 ,但JVM可以屏蔽掉显式的垃圾回收调用,且JVM也有自己的一套垃圾回收机制,那么我们有没有什么办法可以“告诉”JVM,哪些对象是可以使用以后回收,哪些对象保留呢?这里就要说一下JAVA对象的引用类型了。
二、对象引用的简单介绍
- 强引用:无论内存是否足够,不会回收。
- 软引用:内存不足时,回收该引用关联的对象。
- 弱引用:垃圾回收时,无论内存是否足够,都会回收。
- 虚引用:任何时候都可能被垃圾回收器回收。
Java中提供这四种引用类型主要有两个目的:
-
- 1、让程序员通过代码的方式决定某些对象的生命周期;
- 2、第二是有利于JVM进行垃圾回收。
三、对象引用代码示例
强引用
强引用是我们使用的最广泛,也是最普遍的一种引用类型,常见的创建对象的方式就使用的强引用:
//1、强引用示例 String str = new String();
特点:
- 只要某个对象是强引用的,或者有强引用与之关联,JVM必定不会回收这个对象
- 内存不足的情况下,JVM会抛出OutOfMemory错误
- 需要回收时,可以显式设置此对象为null,JVM就会自行在垃圾回收发生时去回收此对象
软引用
软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象:
//2、软引用示例 SoftReference<String> softStr = new SoftReference<String>(new String("这是一个软引用类型的字符串对象")); System.out.println(softStr.get());
软引用相对与强引用来说,比较好的解决了OOM【Out Of Memory】的问题,可以把一些有用的数据,但又不是核心的内容通过软引用的形式来设置,那么当内存不足时就可以回收释放空间了。常见应用如软引用一个图片对象等。
特点:
- SoftReference类包裹引用
- JVM内存不足时会回收【存在强引用关联时不回收】
弱引用
弱引用也是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.WeakReference类来表示。对于弱引用关联着的对象,当JVM进行垃圾回收时,无论内存是否充足,都会回收:
//3、弱引用示例 WeakReference<String> weekStr = new WeakReference<String>(new String("这是一个弱引用类型的字符串对象")); System.out.println(weekStr.get()); //显式调用JVM垃圾回收 System.gc(); //输出弱引用的内容【此时会输出null,因为在显式调用垃圾回收的时候,弱引用对象的内容已经被回收了】 System.out.println(weekStr.get());
PS:如果弱引用对象有对应的强引用关联,那么垃圾回收时是不会回收此弱引用的【软引用也类似】
特点:
- WeakReference类包裹引用
- JVM无论内存充足与否均会在垃圾回收时回收【存在强引用关联时不回收】
虚引用
虚引用不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
//4、虚引用示例 //4.1、创建一个引用队列【虚引用必须跟引用队列关联使用】 ReferenceQueue<String> queue = new ReferenceQueue<String>(); //4.2、创建一个虚引用包裹一个字符串对象的引用地址 PhantomReference<String> phantomStr = new PhantomReference<String>(new String("这是一个虚引用类型的字符串对象"), queue); //4.3、输出引用内容【结果发现输出为null】 System.out.println(phantomStr.get());
特点:
- PhantomReference类包裹引用
- 任何时候都可能被垃圾回收器回收
- 必须跟引用队列关联使用
引用队列(ReferenceQueue)
作用:
- 用于监听Reference所指向的对象是否已经被垃圾回收。
使用场景:
- 当大量使用各种引用(Reference)来包裹实例对象时,虽然引用(Reference)指向的对象可能被回收了,但Reference本身也是个对象,所以也需要回收,这时就需要使用ReferenceQueue了。
回收模式上的区别:
- 当SoftReference或WeakReference的get()加入ReferenceQueue或get()返回null时,仅是表明其指示的对象已经进入垃圾回收流程,此时对象不一定已经被垃圾回收。
- 当PhantomReference加入ReferenceQueue时,则表明对象需要且已被回收【PS:所以虚引用的例子的4.3步骤,调用get方法时返回会为null】。