公共类

  1. public class M {
  2. // 对象被垃圾回收器回收时会触发此方法
  3. @Override
  4. protected void finalize() throws Throwable {
  5. System.out.println("finalize");
  6. }
  7. }

强引用

不会被垃圾回收器回收,因为引用到其它对象,设置为空时 m=null;就会被回收

  1. public class T01_NormalReference {
  2. public static void main(String[] args) throws IOException {
  3. M m = new M(); // 强引用,不会被回收
  4. m = null;
  5. System.gc(); //DisableExplicitGC
  6. System.in.read();
  7. }
  8. }

软引用

当堆内存不够用的时候才会回收

作用

缓存:可以缓存一些大文件,当不需要且内存不够的时候自动回收
idea VM options增加参数-Xms20M -Xmx20M (堆内存最大最小都为20m)

  1. public class T02_SoftReference {
  2. public static void main(String[] args) {
  3. SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
  4. //m = null;
  5. System.out.println(m.get());
  6. System.gc();
  7. try {
  8. Thread.sleep(500);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. System.out.println(m.get());
  13. //再分配一个数组,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
  14. byte[] b = new byte[1024*1024*15];
  15. System.out.println(m.get());
  16. }
  17. }

软引用图示

选区_114.png

弱引用

只要遭到gc就会回收。当有强引用指向它时,强引用不引用它了,它应该被回收掉。

作用

一般用在容器里

  1. public class T03_WeakReference {
  2. public static void main(String[] args) {
  3. WeakReference<M> m = new WeakReference<>(new M());
  4. System.out.println(m.get());
  5. System.gc();
  6. System.out.println(m.get());
  7. ThreadLocal<M> tl = new ThreadLocal<>();
  8. tl.set(new M());
  9. tl.remove();
  10. }
  11. }

虚引用

管理堆外内存的
-Xms20M -Xmx20M

  1. public class T04_PhantomReference {
  2. private static final List<Object> LIST = new LinkedList<>();
  3. private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
  4. public static void main(String[] args) {
  5. PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);
  6. new Thread(() -> {
  7. while (true) {
  8. LIST.add(new byte[1024 * 1024]);
  9. try {
  10. Thread.sleep(1000);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. Thread.currentThread().interrupt();
  14. }
  15. System.out.println(phantomReference.get());
  16. }
  17. }).start();
  18. new Thread(() -> {
  19. while (true) {
  20. Reference<? extends M> poll = QUEUE.poll();
  21. if (poll != null) {
  22. System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);
  23. }
  24. }
  25. }).start();
  26. try {
  27. Thread.sleep(500);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

总结

一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,
也无法通过虚引用来获取一个对象的实例。
为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
虚引用和弱引用对关联对象的回收都不会产生影响,如果只有虚引用活着弱引用关联着对象,
那么这个对象就会被回收。它们的不同之处在于弱引用的get方法,虚引用的get方法始终返回null,
弱引用可以使用ReferenceQueue,虚引用必须配合ReferenceQueue使用。
_jdk中直接内存的回收就用到虚引用,由于jvm自动内存管理的范围是堆内存,
而直接内存是在堆内存之外(其实是内存映射文件,自行去理解虚拟内存空间的相关概念),
所以直接内存的分配和回收都是有Unsafe类去操作,java在申请一块直接内存之后,
会在堆内存分配一个对象保存这个堆外内存的引用,
这个对象被垃圾收集器管理,一旦这个对象被回收,
相应的用户线程会收到通知并对直接内存进行清理工作。
事实上,虚引用有一个很重要的用途就是用来做堆外内存的释放,
DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。_