Java中提供了4种引用类型,强引用、软引用、弱引用、虚引用。只有强引用FinalReference类是包内可见,其他三种均是public,可以直接在应用程序中直接使用。
一、强引用
Java的引用类似C中指针操作,C语言指针 ,通过引用,可以对Java堆内存中的对象进行操作。Java内存模型。
StringBuffer stringBuffer = new StringBuffer("Helloword");
变量str指向了StringBuffer实例所在的堆空间,通过str可以操作这个对象。
强引用特点:
- 强引用可以直接访问目标对象。
- 强引用所在指向的对象在任何时候都不会被系统回收,JVM宁愿抛出OOM异常,也不会回收强引用所指向的对象。
- 强引用可能导致内存泄漏。
二、软引用
软引用是仅次于强引用之外,最强的引用类型,可以通过java.lang.ref.SoftReference使用软引用。持有软引用的对象,不会被JVM,很快回收,JVM会根据当前堆的使用情况来判定何时回收。
若堆使用率接近临界值,则回收软引用对象,可以利用这点实现对内存敏感的高速缓存。
SoftReference特点就是它的一个实例保存了对一个Java对象的软引用,该软引用的存在并不妨碍GC线程对该对象的回收。
设置IDEA堆内存大小为2M:
@Test
public void test3(){
MyObject obj = new myObject();
SoftReference sf = new SoftReference<>(obj);
obj = null;
System.gc();// byte[] bytes = new byte[1024*100];// System.gc();
System.out.println("是否被回收"+sf.get());
}
结果:
是否被回收cn.zyzpp.MyObject@42110406
打开注释的new byte[1024 * 100]语句,这条语句请求一条更大的堆空间,让堆内存紧张,显式调用GC,结果如下:
是否被回收null?
表明软引用被系统回收。
三、弱引用
软引用,弱引用都非常适合保存那些可有可无的缓存数据,若这么做,则系统内存不足时,这些缓存数据会被回收,不会导致内存溢出。而当内存资源充足时,这些缓存数据又可以存在相当长时间,起到系统加速作用。
弱引用在GC时,只要发现弱引用存在,不管系统堆空间是否充足,都会立刻回收对象:
public void test3(){
MyObject obj = new MyObject();
WeakReference sf = new WeakReference(obj);
obj = null;
System.out.println("是否被回收"+sf.get());
System.gc();
System.out.println("是否被回收"+sf.get());
}
四、虚引用
一个持有虚引用的对象,和没有引用几乎一样,随时会被垃圾回收GC,若试图通过虚引用get方法取得强引用,总是失败,并且虚引用和引用队列一起使用,它的作用在于跟踪GC过程。
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,销毁这个对象,将这个虚引用加入引用队列。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动:
public void test3(){
MyObject obj = new MyObject();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference sf = new PhantomReference<>(obj,referenceQueue);
obj = null;
System.out.println("是否被回收"+sf.get());
System.gc();
System.out.println("是否被回收"+sf.get());
}
对虚引用执行get方法:总是返回null。
public T get() {
return null;
}