1,强引用,对象有强引用与之关联,即使在内存不足,抛出OutOfMemory错误也不会回收这种对象 2,软引用是用来描述一些有用但并不是必需的对象,java.lang.ref.SoftReference类来表示。 对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。可以很好地用来解决OOM的问题,适合用来实现缓存:比如网页缓存、图片缓存等。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。 3,弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
在java中,用java.lang.ref.WeakReference类来表示。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,就会被加入到与之关联的引用队列中。 4,虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。 如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。 注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。 弱引用和虚引用的区别是:虚引用总是存在的,只是看存在地方的。而若引用如果没有队列与关联,那么垃圾回收就会没了。如何有关联队列那么两者就一样了。
侧重说下弱引用:因为ThreadLocal用到了弱引用,而线程局部变量被广泛的应用在各种框架中。
了解如何定义和使用:
public class Car { private double price; private String color; public Car(double price, String color) { this.price = price; this.color = color; }
public class WeakReferenceCar extends WeakReference<Car> { public WeakReferenceCar(Car car) { super(car); } }
Car car = new Car(2000.0, "red"); WeakReferenceCar wrc = new WeakReferenceCar(car);
当gc执行:WeakReferenceCar关联的对象Car被回收掉了。
值得注意的是car本身是有强引用的(xxx=new xxx()):
public static void main(String[] args) { Car car = new Car(22000,"silver"); WeakReference<Car> weakCar = new WeakReference<Car>(car); int i=0; while(true){ if(weakCar.get()!=null){ i++; System.out.println("Object is alive for "+i+" loops - "+weakCar); }else{ System.out.println("Object has been collected."); break; } }
即使有 car 引用指向对象, 且 car 是一个strong reference, weakCar指向的对象仍然被回收了.
这是因为java的编译器在发现进入while循环之后, car 已经没有被使用了。
而如果后面有使用是不会被回收的比如下面:
Car car = new Car(22000,"silver"); WeakReference<Car> weakCar = new WeakReference<Car>(car); int i=0; while(true){ System.out.println("here is the strong reference ‘car‘ "+car); if(weakCar.get()!=null){ i++; System.out.println("Object is alive for "+i+" loops - "+weakCar); }else{ System.out.println("Object has been collected."); break; } }
总结:
1,一个变量(该变量是局部变量)是否被回收,看方法是否执行完,一般都被回收的。 但是如果赋值给了其他全局变量,那么是不会被回收的。 2,是否是强引用,一般是不会被回收,但是如果后面没有使用,也是会被回收的。 3,是否是弱引用,一般gc执行就会被回收,
但是如果有强引用关联,那么是不会被回收的, 但是出现第2点的情况,也就是后面不被使用了,也是会被回收的
(其实有强引用关联也就当作强引用的情况在处理了)
补充:对于强引用是否需要手动置空?以便让gc回收。
Object c = new Car(); c=null;
其实是不需要的,手动置空对象对于程序员来说, 是一件繁琐且违背自动回收的理念的.
因为在java中, 对于简单对象, 当调用它的方法执行完毕后, 指向它的引用会被从stack中popup, 所以他就能在下一次GC执行时被回收了
最后一个问题:缓存用哪个引用?
很多人觉得用软引用更好,内存不够再回收。
个人觉得不可以:
据说内存不够时候,清理过程中程序会被挂起,这样很不友好。
而一般启动清理机制,应该是内存使用到达一定程度(应该是可以设置的),运行中的程序还是可以继续执行。