Java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象。
java对象的引用包括:
- 强引用
- 软引用
- 弱引用
- 虚引用
1. 强引用
类似于Object a = new Object()
这类的引用,只要垃圾强引用存在,垃圾回收器就不会回收掉被引用的对象。
public class Demo {
@Override
protected void finalize() throws Throwable {
System.out.println("finalize...");
}
}
public class NormalReferenceDemo {
public static void main(String[] args) throws IOException {
Demo demo = new Demo();
demo = null;
System.gc();
System.in.read();
}
}
运行结果:
2. 软引用
对于软引用关联的对象,在系统将要发生内存溢出异常之前,会把这些对象列入垃圾回收范围中进行回收。如果这次回收还没有足够内存,则抛出内存异常。使用SoftReference
类实现软引用。
执行代码前先配置一下VM启动参数,设置最大堆内存为25M:
public class SoftReferenceDemo {
public static void main(String[] args) {
SoftReference<byte[]> sf = new SoftReference<>(new byte[1024*1024*10]); //10M
System.out.println(sf.get());
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sf.get());
byte[] b = new byte[1024*1024*15]; //15M
System.out.println(sf.get());
}
}
运行结果:
软引用的回收策略在不同的JVM实现会略有不同,javadoc中说明:
Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.
也就是说JVM不仅仅只会考虑当前内存情况,还会考虑软引用所指向的reference最近使用情况和创建时间来综合决定是否回收该referent。
3. 弱引用
强度比软引用更弱,被弱引用关联的对象只能存活到下一次垃圾回收发生之前。当发生GC时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。使用WeakReference
类实现弱引用
public class WeakReferenceDemo {
public static void main(String[] args) {
WeakReference<Demo> demo = new WeakReference<>(new Demo());
System.out.println(demo.get());
System.gc();
System.out.println(demo.get());
}
}
运行结果:
4. 虚引用
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象的实例(PhantomReference的get方法总是返回null)。为一个对象设置虚引用关联的唯一目的就是能够在这个对象被垃圾回收器回收掉后收到一个通知。使用PhantomReference
类实现虚引用
public class PhantomReferenceDemo {
private static final ReferenceQueue<Demo> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<Demo> demo = new PhantomReference<>(new Demo(),QUEUE);
System.out.println(demo.get());
}
}