各个引用的区别
强引用: 强引用指的是通过new对象创建的引用,垃圾回收器即使是内存不足也不会回收强引用指向的对象。
软引用: 软引用是通过SoftRefrence实现的,它的生命周期比强引用短,在内存不足,抛出OOM之前,垃圾回收器会回收软引用引用的对象。软引用常见的使用场景是存储一些内存敏感的缓存,只有当内存不足时会被回收。
弱引用: 弱引用是通过WeakRefrence实现的,它的生命周期比软引用还短,GC只要扫描到弱引用的对象就会回收。弱引用常见的使用场景也是存储一些内存敏感的缓存。
虚引用: 虚引用是通过PhantomRefrence实现的,它的生命周期最短,随时可能被回收。如果一个对象只被虚引用引用,我们无法通过虚引用来访问这个对象的任何属性和方法。get()返回的都是null,它的作用仅仅是保证对象在finalize后,做某些事情。虚引用常见的使用场景是跟踪对象被垃圾回收的活动,当一个虚引用关联的对象被垃圾回收器回收之前会收到一条系统通知。
实验来验证:
- package com.figo.test;
-
- import lombok.Getter;
- import lombok.Setter;
- import org.junit.jupiter.api.Test;
-
- import java.lang.ref.PhantomReference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.WeakReference;
- import java.util.LinkedList;
- import java.util.List;
-
- /**
- * @ClassName:ReferenceTest
- * @PackageName:com.figo.test
- * @Description:类描述
- * @Date:2022/7/20 10:49
- * @Author:figo
- */
- public class ReferenceTest {
- private ReferenceQueue super Employee> referenceQueue;
-
- public class Employee
- {
- @Getter
- @Setter
- String name="andy";
-
- @Getter
- @Setter
- int age=100;
- }
- @Test
- public void testReference(){
- //new出来是强引用
- Employee employee = new Employee();//调用无参构造函数,自动为相关属性赋值
- //软引用,在内存没有出现oom时不会被回收,不能和WeakReference一起使用,否则WeakReference失效
- //SoftReference
employeeSoftReference = new SoftReference<>(employee); - //弱引用
- WeakReference
employeeWeakReference=new WeakReference<>(employee); - //虚引用
- referenceQueue=new ReferenceQueue<>();
- PhantomReference
employeePhantomReference=new PhantomReference<>(employee, referenceQueue); -
- System.out.println("------Before Gc------");
- //System.out.println("软引用对象是否还在="+employeeSoftReference.get());
- System.out.println("弱引用对象是否还在="+employeeWeakReference.get());
- System.out.println("虚引用对象是否还在="+employeePhantomReference.get());
-
- employee=null;//被引用对象清空
- System.gc();//进行垃圾回收, 底部实现Runtime.getRuntime().gc();
-
- System.out.println("------After Gc------");
- //System.out.println("软引用对象是否还在="+employeeSoftReference.get());
- System.out.println("弱引用对象是否还在="+employeeWeakReference.get());
- System.out.println("虚引用对象是否还在="+employeePhantomReference.get());
-
- //向堆中填充数据模拟OOM
- List
list = new LinkedList<>(); - try{
- for (int i = 0; i < 10000; i++) {
- //System.out.println("SoftReference == "+employeeSoftReference.get());
- list.add(new Byte[1*1024*1024]);
- }
- }catch (Throwable e){
- System.out.println("------After OOM------");
- //System.out.println("软引用对象是否还在="+employeeSoftReference.get());
- System.out.println("弱引用对象是否还在="+employeeWeakReference.get());
- System.out.println("虚引用对象是否还在="+employeePhantomReference.get());
- e.printStackTrace();
- }
- }
- }
输出结果:
------Before Gc------
弱引用对象是否还在=com.chinapay.pointconsumer.test.ReferenceTest$Employee@57f23557
虚引用对象是否还在=null
------After Gc------
弱引用对象是否还在=null
虚引用对象是否还在=null
------After OOM------
弱引用对象是否还在=null
虚引用对象是否还在=null
java.lang.OutOfMemoryError: Java heap space
at com.chinapay.pointconsumer.test.ReferenceTest.testReference(ReferenceTest.java:63)
另外提示一下软引用和弱引用不能同时使用,否则gc后发现弱引用引用的对象还是存在的,因为软引用只有在oom后对象才会被当做垃圾回收。
将上面的代码改成注释弱引用后,实验结果:
------Before Gc------
软引用对象是否还在=com.chinapay.pointconsumer.test.ReferenceTest$Employee@57f23557
虚引用对象是否还在=null
------After Gc------
软引用对象是否还在=com.chinapay.pointconsumer.test.ReferenceTest$Employee@57f23557
虚引用对象是否还在=null
------After OOM------
软引用对象是否还在=null
虚引用对象是否还在=null
java.lang.OutOfMemoryError: Java heap space
开发中,对于一些缓存的使用,如果对业务影响不大,在出现内存不足时希望优先被回收的,可以使用SoftReference或者WeakReference。
参考文档:Java:Java的四种引用与其中区别_VoldemortQian的博客-CSDN博客_java四种引用的区别