目录
1. 强引用
强引用是指在程序代码之中普遍存在的,
比如下面这段代码中的object和str都是强引用
Object object = new Object();
String str = "hello";
主要某个对象有强引用与之关联,JVM永远不会回收这个对象,即使内存不足情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
开启垃圾回收器回收强引用演示
想中断引用和某个对象的关联关系,可以显示地将引用赋值为null,JVM在合适的时间会回收这个垃圾
public class T01_NormalReference {
private static class M {
@Override
public void finalize(){
System.out.println("finaliz");
}
}
public static void main(String[] args) throws IOException {
M m = new M();
m = null;
System.gc();
}
}
重写finalize方法, 对象被回收后,会自动启动这个finalize方法
2. 软引用
用来描述一些还有用但并非必须的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之内进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。JDK1.2之后,提供了SoftReference类来实现软引用
public class Main {
public static void main(String[] args) {
SoftReference<String> str = new SoftReference<>(new String("hello"));
System.out.println(str.get());
System.gc();
System.out.println(str.get());
}
}
启动垃圾回收后,还是不会回收,下面演示内存快不足时候,系统会自动回收
演示内存快溢出时,系统自动回收
public class T02_SoftReference {
public static void main(String[] args) {
SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
System.out.println(m.get());
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(m.get());
// 再分配一个数组,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
byte[] b = new byte[1024*1024*15];
System.out.println(m.get());
}
}
第二次打印结果没有被回收
第三次打印结果被回收,因为第一次堆大小10多M左右, 一开始设置了堆大小最大为23M,所以当有新对象创建时,由于10M+15M超过了最大堆,所以系统会在内存溢出之前,自行启动垃圾回收器,对软引用对象进行回收
使用场景
- 图片缓存。图片缓存框架中,“内存缓存”中的图片是以这种引用保存,使得 JVM 在发生 OOM 之前,可以回收这部分缓存。
- 网页缓存。
浏览器实现后退功能:当按浏览器上的后退键时是从缓存中取出数据还是重新构建呢?看下面两种实现策略及问题
(1)如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建
(2)如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出
所以使用软引用来实现浏览器的缓存可以解决上面的两个问题。
public class SoftRefrenceDemo {// js里面有一个goBack()?
public static void main(String[] args) {
Browser prev = new Browser(); // 获取页面进行浏览
SoftReference<Browser> sr = new SoftReference<Browser>(prev); // 浏览完毕后置为软引用
if (sr != null) {
prev = (Browser) sr.get(); // 还没有被回收器回收,直接获取
} else {
prev = new Browser(); // 由于内存吃紧,所以对软引用的对象回收了
sr = new SoftReference<Browser>(prev); // 重新构建
}
}
}
class Browser {
}
3. 弱引用
弱引用是用来描述非必须对象的,它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference类来实现弱引用
public class Main {
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<>(new String("hello"));
System.out.println(sr.get());
System.gc(); //通知JVM的gc进行垃圾回收
System.out.println(sr.get());
}
}
4. 虚引用
虚引用也成为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。在JDK1.2之后,提供了PhantomReference类来实现虚引用
注意: Java虚拟机不负责清理虚引用,但是它会把虚引用放到引用队列里面.
虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
public class Main {
public static void main(String[] args) {
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> pr = new PhantomReference<>(new String("hello"), queue);
System.out.println(pr.get());
}
}