一、强引用

  1. 只要某个对象与强引用关联,那么JVM在内存不足的情况下,宁愿抛出outOfMemoryError错误,也不会回收此类对象。

强引用声明格式:

  1. String str="abc";
  1. 如果我们想要JVM回收此类被强引用关联的对象,我们可以显示地将str置为null,那么JVM就会在合适的时间回收此对象。

二、软引用

  1. java中使用SoftRefence来表示软引用,如果某个对象与软引用关联,那么JVM只会在内存不足的情况下回收该对象。
  1. import java.lang.ref.SoftReference;
  2. public class TestRef {
  3. public static void main(String args[]) {
  4. SoftReference<String> str = new SoftReference<String>(new String("abc"));
  5. System.out.println(str.get());
  6. //通知JVM进行内存回收
  7. System.gc();
  8. System.out.println(str.get());
  9. }
  10. }
  1. 软引用适合做缓存,在内存足够时,直接通过软引用取值,无需从真实来源中查询数据,可以显著地提升网站性能。当内存不足时,能让JVM进行内存回收,从而删除缓存,这时候只能从真实来源查询数据。

三、弱引用

  1. java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联,那么当JVM在进行垃圾回收时,无论内存是否充足,都会回收此类对象。
  1. import java.lang.ref.WeakReference;
  2. public class TestRef {
  3. public static void main(String args[]) {
  4. WeakReference<String> str = new WeakReference<String>(new String("abc"));
  5. System.out.println(str.get());
  6. //通知JVM进行内存回收
  7. System.gc();
  8. System.out.println(str.get());
  9. }
  10. }
  1. System.out.println(str.get());有可能取不到str的值。这是因为我们在声明了弱引用之后,立即对其输出,而gc线程是一个优先级很低的守护线程,还来不及扫描该该对象所在的区域,即来不及对该对象的回收。如果我们在声明之后的很长时间后,再次get,是有可能get不到值的。
  2. 弱引用可以在回调函数在防止内存泄露。因为回调函数往往是匿名内部类,一个非静态的内部类会隐式地持有外部类的一个强引用,当JVM在回收外部类的时候,此时回调函数在某个线程里面被回调的时候,JVM就无法回收外部类,造成内存泄漏。在安卓activity内声明一个非静态的内部类时,如果考虑防止内存泄露的话,应当显示地声明此内部类持有外部类的一个弱引用。

四、虚引用

  1. java中使用PhantomReference来表示虚引用。虚引用,虚引用,引用就像形同虚设一样,就像某个对象没有引用与之关联一样。若某个对象与虚引用关联,那么在任何时候都可能被JVM回收掉。虚引用不能单独使用,必须配合引用队列一起使用。
  1. import java.lang.ref.PhantomReference;
  2. import java.lang.ref.ReferenceQueue;
  3. public class TestRef {
  4. public static void main(String args[]) {
  5. ReferenceQueue<String> queue = new ReferenceQueue<>();
  6. PhantomReference<String> str = new PhantomReference<String>("abc", queue);
  7. System.out.println(str.get());
  8. }
  9. }
  1. 当垃圾回收器准备回收一个对象时,如果发现它与虚引用关联,就会在回收它之前,将这个虚引用加入到引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被回收,如果确实要被回收,就可以做一些回收之前的收尾工作。