Java中对java对象引用有四种类型:强引用、软引用、弱引用和虚引用。在这四种引用中,只有强引用包内可见FinalReference类,其他三种引用类型均为public,可直接用于应用程序。
Java内存管理分为内存分配和内存回收。垃圾回收的机制主要取决于对象是否引用指向对象。因此,Java主要提供这四种引用类型是程序员可以通过代码确定某些对象的生命周期,同时有利于垃圾回收的JVM。让我们来分析一下java对像引用的四种类型:
- 强引用
Java中的引用类似于C语言中最困难的指针。事实上,它是创建一个对象并将该对象赋予一个引用变量。通过引用,可以操作堆中的对象。我们通常使用new操作符创建的对象是强引用对象。只要有引用,垃圾回收器就永远无法回收强引用对象。
Object obj=new Object();
强引用可以直接访问目标对象。强引用的对象永远不会被回收,需要使用obj值为null,或超过对象的生命周期后,GC有机会回收,具体时间取决于GC。此外,这里的Strongrefererence只是一个强引用的名称,在java中没有相应的物理类别。例如:
publicclassMain{
publicstaticvoidmain(String[]args){
newMain().fun1();
}
publicvoidfun1(){
Objectobject=newObject();
Object[]objArr=newObject[1000];
}
当运行至Object[] objArr = new Object[1000];在这句话中,如果内存不足,JVM会抛出OOM错误,也不会回收Object指向的对象。但需要注意的是,当fun1运行时,object和objarr已经不存在,因此它们指向的对象将被JVM回收。在使用强引用的过程中,还应注意强引用可能导致内存泄漏。
二、软引用
软引用是除强引用外最强的引用类型。可以通过java.lang.ref.Softreference使用软引用。如果一个对象有软引用,有足够的内存空间,垃圾回收器就不会回收。软引用对象只有在堆利用率接近阈值时才能回收。因此,软引用可用于实现对内存敏感的高速缓存。如果内存空间不足,这些对象的内存将被回收利用。程序可以使用垃圾回收器,只要垃圾回收器不回收。软引用可用于实现网页缓存、图片缓存等内存敏感的高速缓存。使用软引用可以防止内存泄漏,增强程序的强度。Softreference的特点是它的一个实例保存了对Java对象的软引用, 该软引用的存在并不妨碍垃圾收集线程对Java对象的回收。
也就是说,一旦Softreference保存了对Java对象的软引用后,在垃圾线程中 在Java对象回收之前,Softreference类提供的get()方法返回Java对象的强引用。此外,一旦Java对象被垃圾线程回收,get()方法将返回null。以下是一个简单的例子:
MyObject aRef = new MyObject();
SoftReference aSoftRef=new SoftReference(aRef);
这个时候,对于这个Myobject对象有两种引用路径,一种是Softreference对象的软引用,另一种是变量areference的强引用,因此Myobject对象是强可及的对象。
我们可以马上结束areference对这个Myobject实例的强引用:
aRef = null;
此后,这个Myobject对象成为软引用对象。如果垃圾收集线程用于内存垃圾收集,则不会因为Softreference引用对象而始终保留对象。
Java虚拟机的垃圾收集线程区别对待软可及对象和其他一般Java对象:软可及对象的清理由垃圾收集线程根据其特定算法和内存需求确定。
也就是说,垃圾收集线程会在虚拟机上抛出outofmemoryerror之前回收软可及对象,虚拟机会尽可能优先回收长期闲置的软可及对象,对于刚刚建造或刚刚使用的对象“新”虚拟机将尽可能保留软可反对象。在回收这些对象之前,我们可以通过:
name="code" class="java">MyObject anotherRef=(MyObject)aSoftRef.get(); 重新获得这个例子的强引用。回收后,只能通过调用get()来获得null。
三、弱引用
弱引用是比软引用弱的引用类型。在系统中GC时,只要发现弱引用,无论系统堆积空间是否足够,对象都会回收。java可用于java.lang.ref.为了保存对Java对象的弱引用,Weakreference实例。
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());
}
运行结果:
是否被回收cn.zyzpp.MyObject@42110406
是否被回收null
软引用和弱引用非常适合保存可有可无的缓存数据。如果这样做,当系统内存不足时,这些缓存数据将被回收,不会导致内存溢出。当内存资源充足时,这些缓存数据可以长期存在,从而加速系统。
4.虚引用
虚引用,又称幻象引用,如果一个对象有虚引用,那么它就像没有任何引用一样,通过虚引用相关对象引用获取的方法总是null,也就是说,这个对象随时都可能被垃圾回收器回收,这样相关的对象就无法调用对象中的方法。虚假引用主要用于管理堆外内存,通过referenceQueue实现。当一个对象被回收时,相关数据将添加到引用列中并给出通知。
当垃圾回收器准备回收一个对象时,如果发现它仍然有一个虚拟引用,它将在垃圾回收后销毁该对象,并将该虚拟引用添加到引用队列中。该程序可以判断引用队列中是否添加了虚拟引用,以了解被引用对象是否将被垃圾回收。如果该程序发现一个虚拟引用已被添加到引用队列中,则可以在引用对象的内存被回收之前采取必要的行动。
public void test3(){
MyObject obj = new MyObject();
ReferenceQueue referenceQueue = new ReferenceQueue<>();
PhantomReference sf = new PhantomReference<>(obj,referenceQueue);
obj = null;
System.out.println("是否被回收"+sf.get());
System.gc();
System.out.println("是否被回收"+sf.get());
}
运行结果:
是否被回收null
是否被回收null
对虚引用的get()操作总是返回null,因为sfl.get()方法的实现如下:
public T get() {
return null;
}
对于强引用,我们通常在编写代码时使用它。对于其他三种类型的引用,最常用的是软引用和弱引用,这两者既有相似之处又有不同之处。它们都被用来描述不必要的对象,但软引用相关对象只有在内存不足时才会被回收,而弱引用相关对象在JVM垃圾回收时总是被回收。
Softreference类有三种方法,两种结构方法和一种get方法(Wekreference类似):
两种结构方法:
publicSoftReference(Treferent){
super(referent);
this.timestamp=clock;
}
publicSoftReference(Treferent,ReferenceQueueq){
super(referent,q);
this.timestamp=clock;
}
获取方法用于获取与软引用相关的对象的引用,如果对象被回收,则返回null。
使用软引用和弱引用时,我们可以通过System显示.gc()通知JVM回收垃圾,但需要注意的是,JVM虽然发出通知,但可能不会立即实施,也就是说,这句话不能保证此时JVM垃圾回收肯定会进行。
很多时候,一个对象不是直接从根集引用的,而是一个对象被其他对象引用,甚至同时被几个对象引用,从而形成以根集为顶的树形结构。
只有掌握了四种引用类型,才能掌握java编程得心应手,当然,如果只靠这篇文章是做不到的,一定要对引用类型的知识有更深入的了解和学习。“纸上得来终觉浅,绝知此事要实践。”只有通过不断编写过程中的实际应用,才能充分掌握java中的四种引用。