一个自定义类
1 2 3 4 5 6
| public class M { @Override protected void finalize() throws Throwable { System.out.println("finalize"); } }
|
finalize() 方法,在该对象要被垃圾回收的时候被调用
强引用
- 平常所用的那些普通的引用,如B a=new B()
- 当有强引用指向某对象时,该引用一定不会被垃圾回收
- 当内存空间不足的时候,java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会随意回收具有强引用的对象来解决内存不足的问题。
- 可以使用a = null的方式切断强引用
1 2 3 4 5 6 7 8 9
| public class DemoNormalReference { public static void main(String[] args) throws IOException { M m = new M(); m = null; System.gc();
System.in.read(); } }
|

System.gc() 调用附带一个免责声明,无法保证对垃圾收集器的调用。
但是这里最好写上,大概率是可以调用的。如果不写,在内存空闲较多的情况下,会一直等待,看不到效果。
软引用
- 如果内存空间足够,垃圾回收器就不会回收软引用所指向的对象;如果空间不足了,就会回收这些对象的内存。
- 只要垃圾回收器没有回收它,该对象就可以被程序使用。
- 软引用可以用来实现缓存。内存空余,使用缓存;内存不足,释放缓存。
- 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,java虚拟机就会把这个软引用对象加入到与之关联的引用队列中
- 最后来讲:软引用是一个对象,它所引用的对象被认为被软引用指向

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public class DemoSoftReference { 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(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(m.get());
byte[] b = new byte[1024*1024*15]; System.out.println(m.get()); } }
|
虚拟机参数设定

结果展示

弱引用
1 2 3 4 5 6 7 8
| public class DemoWeakReference { public static void main(String[] args) { WeakReference<M> m = new WeakReference<>(new M()); System.out.println(m.get()); System.gc(); System.out.println(m.get()); } }
|

用途:在某些场合,常用来使虚拟机在某些时候明确其是垃圾【废话】
借鉴网上博主一段话,【此段自己已经理解,保证准确性】:
考虑下面的场景:现在有一个Product类代表一种产品,这个类被设计为不可扩展的,而此时我们想要为每个产品增加一个编号。一种解决方案是使用HashMap<Product, Integer>。于是问题来了,如果我们已经不再需要一个Product对象存在于内存中(比如已经卖出了这件产品),假设指向它的引用为productA,我们这时会给productA赋值为null,然而这时productA过去指向的Product对象并不会被回收,因为它显然还被HashMap引用着。所以这种情况下,我们想要真正的回收一个Product对象,仅仅把它的强引用赋值为null是不够的,还要把相应的条目从HashMap中移除。显然“从HashMap中移除不再需要的条目”这个工作我们不想自己完成,我们希望告诉垃圾收集器:在只有HashMap中的key在引用着Product对象的情况下,就可以回收相应Product对象了。显然,根据前面弱引用的定义,使用弱引用能帮助我们达成这个目的。我们只需要用一个指向Product对象的弱引用对象来作为HashMap中的key就可以了。
摘自——-理解java中的弱引用
如上的论述在ThreadLocal的源码中也有清晰的体现,有效防止了内存的泄漏
虚引用
- 虚引用根本就不像是一个引用,无论什么情况get()方法的返回值都是一个null
- 如果一个对象只有虚引用指向它了,那么它一定会被垃圾回收
- 它最好和ReferenceQueue关联(不然不知道其有什么用),当其引用的对象被垃圾回收,其自身被加入到引用队列中,从这个队列中我们就可以得知,哪些虚引用指向的对象被垃圾回收了
- 主要用途是用于检测对象是否已经从内存中删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class DemoPhantomReference { private static final List<Object> LIST = new LinkedList<>(); private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
public static void main(String[] args){ PhantomReference<M> phantomReference = new PhantomReference<>(new M(),QUEUE);
new Thread(()->{ while(true){ LIST.add(new byte[1024*1024*10]); try{ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } System.out.println(phantomReference.get()); } }).start();
new Thread(()->{ while(true){ Reference<? extends M> poll = QUEUE.poll(); if(poll != null){ System.out.println("--- 虚引用对象所引用的对象被jvm回收了 ----" + poll); } } }).start(); } }
|

总结
总之,合理的使用引用可以帮助垃圾回收器更好的管理Java内存。