美文网首页Android进阶之路
Java中的JVM强软弱虚引用

Java中的JVM强软弱虚引用

作者: 码农的地中海 | 来源:发表于2022-05-17 19:25 被阅读0次

概述:

在java中,除了基本数据类型的变量外,其他所有的变量都是引用类型,指向堆上各种不同的对象。

Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。

强引用

强引用(Strong references)就是直接new一个普通对象,表示一种比较强的引用关系,只要还有强引用对象指向一个对象,那么表示这个对象还活着,垃圾收集器宁可抛出OOM异常,也不会回收这个对象。

例如下面的引用u就是一个强引用。

1. public class StrongReferenceDemo {
2.     public static void main(String[] args) throws IOException {
3.         User u = new User();
4.         System.out.println(u);
5.         u = null;
6.         System.gc();
7.       System.in.read();   
8.  } 
9. }

10. public class User {

11.   @Override    
12. protected void finalize() throws Throwable {    
13.     System.out.println("call User finalize() method");   
14.  } 
15. } 

上面的User对象重写了父类Object的finalize(),在GC准备释放对象所占用的内存空间之前,它将首先调用finalize()方法。

在Java中,由于GC的自动回收机制,因而并不能保证finalize方法会被及时地执行(垃圾对象的回收时机具有不确定性),也不能保证它们会被执行(程序由始至终都未触发垃圾回收),所以finalize不推荐使用,这里只是为了演示垃圾回收的过程。

另外finalize()最多只会被调用一次,也就是只能利用finalize()为对象续命一次。

软引用

软引用用于存储一些可有可无的东西,例如缓存,当系统内存充足时,这些对象不会被回收,当系统内存不足时也是GC时才会回收这些对象,如果回收完这些对象后内存还是不足,就会抛出OOM异常。

1. // vm args: -Xmx36m -XX:+PrintGCDetails
2. public class SoftReferenceDemo {
3.     public static void main(String[] args) throws InterruptedException {
4.  SoftReference<User> softReference = new SoftReference<>(new User()); *// 软引用*      
5.    System.out.println(softReference.get()); 
6.  System.gc();          
7. TimeUnit.SECONDS.sleep(3); *// wait gc thread run* 
8.  System.out.println(softReference.get()); *// User对象不会被回收* 
9.   byte[] bytes = new byte[1024 * 1024 * 10]; *// 分配一个大对象使得堆空间不足,软引用对象会在OOM之前先被回收*      
10.   System.out.println(softReference.get()); 
11.  }
12.  } 

在上面的例子中,第一次发生gc时,User对象不会被回收,第二次发生gc时由于堆空间不足,会先回收软引用的对象,回收完了还是空间不足,最后抛出OOM异常。

弱引用

弱引用(WeakReference)并不能使对象豁免垃圾回收,仅仅是提供一种访问在弱引用状态下对象的途径。只要发生gc,弱引用对象就会被回收。ThreadLocal中就使用了WeakReference来避免内存泄漏。

1. public class WeakReferenceDemo{     
2. public static void main(String[] args) throws InterruptedException { 
3.   WeakReference<User> weakReference = new WeakReference<>(new User());   
4.   System.out.println(weakReference.get()); 
5.  System.gc();        
6.  TimeUnit.SECONDS.sleep(3); *// wait gc thread run* 
7.  System.out.println(weakReference.get()); *// null*  
8.   } 
9. } 

上面的例子只要发生gc,User对象就会被垃圾收集器回收。

虚引用

虚引用必须和引用队列(ReferenceQueue)联合使用。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

虚引用主要用来跟踪对象被垃圾回收的活动。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象之前,把这个虚引用加入到与之关联的引用队列中。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

1.  *// vm args: -Xms4m -XX:+PrintGC* public class 
2. PhantomReferenceDemo { 
3. 
4. public static void main(String[] args) throws IOException, InterruptedException {
5. ReferenceQueue<User> referenceQueue = new ReferenceQueue<>(); // 引用队列
6. PhantomReference<User> phantomReference = new PhantomReference<>(new User(), referenceQueue); // 虚引用
7.  System.out.println(phantomReference.get()); *// null* 
8.  new Thread(() -> {
9.             while (true) {
10.                 Reference<? extends User> poll = 
11. referenceQueue.poll();
12.                 if (poll != null) {
13.                     System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);
14.                     System.out.println("--- 回收对象 ---- " + poll.get()); // null
15.  }     
16.        }    
17.     }).start();        
18.  TimeUnit.SECONDS.sleep(1);        
19.  System.gc();         
20. System.in.read(); 
21.     } 
22. private static class User {     
23.    private int[] bytes = new int[1024 * 1024 * 5]; 
24. @Override        
25. protected void finalize() throws Throwable {      
26.       System.out.println("call User finalize() method"); 
27.  }   
28.  } 
29. } 

实际上,虚引用的get()方法总是返回null。

基于虚引用,有一个更加优雅的实现方式,那就是Cleaner,可以用来替代Object类的finalizer方法,在DirectByteBuffer中用来回收堆外内存。

总结

通过这篇文章介绍了 Java 语言中的四种引用类型,看完后我们发现这主要与Java 的垃圾回收机制和内存管理息息相关。JVM 作为基础,还是希望大家能够扎实的掌握。

自己在职Android开发5年有余,几年积累整合了一些https://shimo.im/docs/1d3aV7zG5gF6Eyqg/ Android开发核心进阶技术文档,。
想有收获必须有努力,知识在于积累。不进则退。

相关文章

  • Java中的JVM强软弱虚引用

    概述: 在java中,除了基本数据类型的变量外,其他所有的变量都是引用类型,指向堆上各种不同的对象。 Java 对...

  • Java基础:Java的四种引用

    在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用。包括:强引用,软引用,弱引用,虚引用。这...

  • 对象的引用

    一、概述 Java对象的引用:强引用,软引用,弱引用和虚引用。众所周知,Java中是JVM负责内存的分配和回收,这...

  • Java中的四种引用类型(强、软、弱、虚)

    Java中的四种引用类型(强、软、弱、虚) 从Java1.2开始,JVM开发团队发现,单一的强引用类型,无法很好的...

  • Java强软弱虚引用

    在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及...

  • Java中的四种引用

    1.强软弱虚四种引用 1.1 强引用 执行结果: 解释:强引用是JVM的默认实现,即使内存不足会导致OOM(Out...

  • java中强软弱虚引用类型

    概念 java中之所以会有强引用、软引用、弱引用、虚引用这些概念,是为了方便内存回收。 强引用即便内存不足,oom...

  • 深入理解Java中的引用(二)——强软弱虚引用

    深入理解Java中的引用(二)——强软弱虚引用 在上一篇文章中介绍了Java的Reference类,本篇文章介绍他...

  • Android面试题大全-Java基础篇

    Java基础 内存泄漏的场景 强软弱虚引用分别什么区别 什么场景下使用虚引用 ClassLoader的双亲委派原理...

  • java中强软弱虚引用的妙用

    前言 ThreadLocal 在什么情况下可能发生内存泄漏?如果你想清楚这个问题的来龙去脉,看源码是必不可少的,看...

网友评论

    本文标题:Java中的JVM强软弱虚引用

    本文链接:https://www.haomeiwen.com/subject/jtinurtx.html