static class Person {
String mName;
public Person(String name) {
mName = name;
}
@Override
public String toString() {
return "person[" + mName + "]";
}
}
1.强软弱虚四种引用
1.1 强引用
public static void strongRef() {
try {
Person person = new Person("张三");
Person strong = person;
person = null;
System.gc();
Thread.sleep(1000);
System.out.println(strong);
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果:
person[张三]
解释:
强引用是JVM的默认实现,即使内存不足会导致OOM(OutOfMemory)时,强引用关联的对象也不会被回收。
1.2 软引用
public static void softRef() {
try {
Person person = new Person("李四");
ReferenceQueue<Person> rq = new ReferenceQueue<Person>();
SoftReference<Person> sr = new SoftReference<Person>(person, rq);
person = null;
System.gc();
Thread.sleep(1000);
System.out.println("sr.get():" + sr.get());
System.out.println("rq.poll():" + rq.poll());
} catch (Exception e) {
e.printStackTrace();
}
}
内存足够的情况下的执行结果:
sr.get():person[李四]
rq.poll():null
内存不足的情况下的执行结果:
sr.get():null
rq.poll():java.lang.ref.SoftReference@15db9742
解释:
- 某个对象只被软引用关联,当JVM内存不足时,该对象会被回收。也就是说在JVM抛出OutOfMemoryError之前,会去清理只被软引用关联的对象。
- 软引用可以与引用队列ReferenceQueue联合使用。当只被软引用关联的对象(即Person对象)被回收后,其相应的包装类对象(即SoftReference对象)会被加入到ReferenceQueue队列中。
- 包装类对象被加入到ReferenceQueue队列中后,调用其
poll()
方法可以获取该队列中的包装类对象。
1.3 弱引用
public static void weakRef() {
try {
Person person = new Person("王五");
ReferenceQueue<Person> rq = new ReferenceQueue<Person>();
WeakReference<Person> wr = new WeakReference<Person>(person, rq);
System.out.println("wr.get():" + wr.get());
person = null;
Reference<?> reference;
while (true) {
System.out.println("-----");
reference = rq.poll();
if (wr.equals(reference)) {
System.out.println("wr.get():" + wr.get());
System.out.println("被回收了");
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果:
wr.get():person[王五]
----
----
----
...
wr.get():null
被回收了
解释:
当某个对象只被弱引用关联时,无论内存是否足够,只要 JVM 开始进行垃圾回收,该对象都会被回收。
1.4 虚引用
public static void phantomRef() {
Person person = new Person("朱六");
ReferenceQueue<Person> rq = new ReferenceQueue<>();
PhantomReference<Person> pr = new PhantomReference<MyTest.Person>(person, rq);
System.out.println("pr.get():" + pr.get());
person = null;
Reference<?> reference;
while (true) {
System.out.println("-----");
reference = rq.poll();
if (pr.equals(reference)) {
System.out.println("被回收了");
break;
}
}
}
执行结果:
pr.get():null
-----
-----
-----
...
被回收了
解释:
- 虚引用必须与引用队列ReferenceQueue联合使用
- 虚引用的
get()
方法永远返回null - 当JVM发现一个对象只被虚引用关联时,则会将虚引用加入ReferenceQueue队列中,然后当JVM垃圾回收时回收该对象
注意:虚引用是先将包装类PhantomReference对象加入ReferenceQueue队列中,然后Person对象才被JVM回收;而软引用和弱引用则相反,是Person对象先被JVM回收,然后才...
2.四种引用的应用场景:
- 强引用,不解释。
- 软引用,适用于网页、图片、视频等缓存。
比如app内有一张图片,这张图片很多地方都会用到,如果每次用到的时候都去读取图片,大量的重复读取会导致性能下降,此时可以将图片缓存起来,需要的时候直接从内存中读取,但是由于图片占的内存空间比较大,缓存的图片过多就有可能发生OOM,这时就可以使用软引用。 - 弱引用,适用于可能会发生内存泄漏的地方。比如Android中的Handler,参见博客Android Handler详解
- 虚引用,在程序中可以判断PhantomReference是否已经被加入ReferenceQueue队列中,如果是,则说明虚引用关联的对象即将被回收,可以在回收之前执行一些必要的业务逻辑。
网友评论