Java引用详解
原文链接:https://blog.csdn.net/sunxianghuang/article/details/52267282
https://www.cnblogs.com/yw-ah/p/5830458.html
强引用(Strong Reference)
强引用是指在程序代码中普遍存在的,类似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
public class StrongReferenceTest { private static class BiggerObject{//占用空间的一个大对象 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=10000;//对象的个数,保证使得堆内存溢出 BiggerObject[] values=new BiggerObject[count]; for(int i=0;i<count;i++){ values[i]=new BiggerObject("Object-"+i); } for(int i=0;i<10;i++){ System.out.println(values[i].name); } } }
输出:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid668.hprof ... Heap dump file created [13980085 bytes in 0.181 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at StrongReferenceTest$BiggerObject.<init>(StrongReferenceTest.java:8) at StrongReferenceTest.main(StrongReferenceTest.java:15)
因为垃圾收集器无法回收强引用关联着的对象,从而导致堆内存溢出。
软引用(Soft Reference)
用来描述一些还有用并非必要的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。JDK 1.2之后,提供了SoftReference类来实现软引用。
import java.lang.ref.SoftReference; public class SoftReferenceTest { private static class BiggerObject{//占用空间的一个大对象 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100000;//对象数量为100000,保证使得堆内存溢出 SoftReference[] values=new SoftReference[count]; for(int i=0;i<count;i++){ values[i]=new SoftReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
输出:
Object-99999 Exception in thread "main" java.lang.NullPointerException at SoftReferenceTest.main(SoftReferenceTest.java:21)
第一行输出说明,使用软引用后,原本由于堆内存溢出而无法正常执行的代码段“正常的”执行成功;
但是,当我们访问早期创建的那些对象时,却报java.lang.NullPointerException异常,说明早期创建的对象已经被垃圾收集器回收了。
import java.lang.ref.SoftReference; public class SoftReferenceTest { private static class BiggerObject{//占用空间的一个大对象 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100;//对象数量改为100,保证堆内存不会溢出 SoftReference[] values=new SoftReference[count]; for(int i=0;i<count;i++){ values[i]=new SoftReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.gc();//强制进行垃圾回收 System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
输出:
Object-99 Object-0 Object-1 Object-2 Object-3 Object-4 Object-5 Object-6 Object-7 Object-8 Object-9
当堆内存足够时,即使我们强制进行垃圾回收,软引用关联着的对象也不会被回收。
弱引用(WeakReference)
弱引用也是用来描述非必要对象的,但是他的强度比软引用更弱一些,被软引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。JDK 1.2之后,提供了WeakReference类来实现弱引用。
public class WeakReferenceTest { private static class BiggerObject{//占用空间的一个大对象 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=10000;//对象数量为10000,保证使得堆内存溢出 WeakReference[] values=new WeakReference[count]; for(int i=0;i<count;i++){ values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
输出:
Object-9999 Exception in thread "main" java.lang.NullPointerException at WeakReferenceTest.main(WeakReferenceTest.java:22)
输出结果,与软引用相同。
public class WeakReferenceTest { private static class BiggerObject{//占用空间的一个大对象 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100;//对象数量改为100,保证堆内存不会溢出 WeakReference[] values=new WeakReference[count]; for(int i=0;i<count;i++){ values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
输出:
Object-99 Object-0 Object-1 Object-2 Object-3 Object-4 Object-5 Object-6 Object-7 Object-8 Object-9
当堆内存够用时,正常输出。
public class WeakReferenceTest { private static class BiggerObject{//占用空间的一个大对象 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100;//对象数量改为100,保证堆内存不会溢出 WeakReference[] values=new WeakReference[count]; for(int i=0;i<count;i++){ values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); System.gc();//强制进行垃圾回收 for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
即使堆内存够用,当我们强制进行垃圾回收时,弱引用所引用的对象还是被垃圾收集器回收。
虚引用
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现
Object obj = new Object(); PhantomReference<Object> pf = new PhantomReference<Object>(obj); obj=null; pf.get();//永远返回null pf.isEnQueued();//返回是否从内存中已经删除
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
虚引用主要用于检测对象是否已经从内存中删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)