java中的强引用、软引用、弱引用、虚引用

简介: java中将引用类型分为强引用、软引用、弱引用、虚引用。之所以要这么划分,还是为了GC时更好的对对象进行处理。因为jvm已经明确了各种引用的GC方式,所以谈四种引用最好是和GC一起聊才会有意义(个人愚见)。

强引用、软引用、弱引用、虚引用



java中将引用类型分为强引用、软引用、弱引用、虚引用。之所以要这么划分,还是为了GC时更好的对对象进行处理。因为jvm已经明确了各种引用的GC方式,所以谈四种引用最好是和GC一起聊才会有意义(个人愚见)。


强引用


java中正常声明的变量都是强引用,比如:


String str = "Hello";
String stri = new String("Hello");


强引用只要是在栈空间仍存在指向堆中的引用就不会被回收。


怎么回收强引用?


1.类变量,声明过以后,在不使用时应做null处理。这样GC才会处理他,至于是不是下一次GC则不一定了。


2.局部变量,基本会在方法或者代码块执行完成之后就会GC,如果被其他变量引用了,仍存在引用链则不会回收。


软引用


软引用需要使用java提供的SoftReference来包装,如下则是软引用的声明方式:


String str = "abc";
SoftReference<String> sf = new SoftReference<String>(str);
String strRefe =  sf.get();
System.out.println(strRefe);
输出结果:
abc
Process finished with exit code 0


怎么回收软引用?


1.软引用会在jvm报OOM之前,将所有软引用全部清除,也就是说jvm内存吃紧会去清理软引用。


2.GC在回收软可达对象时,会回收软引用,回收这些软引用的对象时会判断该对象是不是不可达了,可达则不会回收。


举个例子证明内存紧张时软应用不会一定回收,因为这些对象仍是可达的:


public class TestHeapOom {
    static class OOMObject{
       String name;
       public OOMObject(String name){
           this.name = name;
       }
    }
    public static void main(String[] args){
        int n =0;
        List<OOMObject> list = new ArrayList<OOMObject>();
        SoftReference<List<OOMObject>> sr = new SoftReference<List<OOMObject>>(list);
        System.out.println(sr.get().size());
        while (true){
            list.add(new OOMObject("a"+n));
            System.out.println(sr.get().size());
        }
    }
}


程序输出:


1
1
...
106063
106064
106065
106066
106067
106068
106069
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
  at com.example.demo.OOM.TestHeapOom.main(TestHeapOom.java:34)
Process finished with exit code 1


输出结果解析:可以看到跑出的异常是“GC overhead limit exceeded”,该错误的意思是cpu98%时间在执行垃圾回收,但回收到的内存仍是非常小,会抛出该异常。如果这个程序不加软引用则抛出的是“Java heap space”,因为内存紧张程序就会试图回收软应用,则会一直运行GC,但是这些软应用仍是可达的,又回收不了,故会一直GC,却回收不到内存,就会有“GC overhead limit exceeded”这种异常。


弱引用


软引用需要使用java提供的WeakReference来包装,如下则是软引用的声明方式(此外java中的WearHashMap中的key默认就是弱引用,若是只有map引用这些对象,则会被回收):


WeakReference<String> wf = new WeakReference<String>(str);
String strRew = wf.get();
System.out.println(strRew);
输出结果:
abc
Process finished with exit code 0


怎么回收弱引用?


会在下一次gc时直接回收弱引用内存(不一定是一次gc就全部回收,且该对象必须是不可达才会回收,使用上面的例子仍然可以证明)


虚引用


软引用需要使用java提供的WeakReference来包装,虚引用是无法通过get得到值的,得到的永远会是null,如下则是软引用的声明方式:


ReferenceQueue rq = new ReferenceQueue();
PhantomReference<String> pf = new PhantomReference<String>(str,rq);
System.out.println(pf.get());


怎么回收虚引用?

虚引用会被直接回收,所以无法通过虚引用获得一个对象实例,但是被虚引用关联的对象何时回收其实不受任何影响,判断对象会不会回收依据仍然是jvm的可达性分析算法,为一个对象设置虚引用关联的唯一目的只是在这个对象被垃圾收集器回收时收到一个系统通知,判断虚引用关联的对象会不会回收仍然可用软引用中的例子。

————————————————

版权声明:本文为CSDN博主「归去来 兮」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/m0_46897923/article/details/109337874

相关文章
|
9月前
|
缓存 Java 程序员
Java面试题:解释强引用、软引用、弱引用和虚引用在Java中是如何工作的?
Java面试题:解释强引用、软引用、弱引用和虚引用在Java中是如何工作的?
64 1
|
10月前
|
缓存 Java 数据库连接
java面试题目 强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
【6月更文挑战第28天】在 Java 中,理解和正确使用各种引用类型(强引用、软引用、弱引用、幻象引用)对有效的内存管理和垃圾回收至关重要。下面我们详细解读这些引用类型的区别及其具体使用场景。
129 3
|
9月前
|
Java 运维
开发与运维引用问题之软引用又在Java特点如何解决
开发与运维引用问题之软引用又在Java特点如何解决
71 0
|
10月前
|
缓存 监控 算法
【Java】谈一谈虚引用
【Java】谈一谈虚引用
145 0
|
11月前
|
缓存 Java
【JAVA】强引用、软引用、弱引用、幻象引用有什么区别?
幻象引用:幻象引用是最弱的引用类型,几乎不影响对象的生命周期。它们主要用于在对象被回收前进行某些预处理操作,例如在对象被销毁时执行特定的清理任务。
87 0
|
11月前
|
Java
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
602 0
|
11月前
|
缓存 Java 程序员
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
102 2
|
2月前
|
存储 监控 Java
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
213 60
【Java并发】【线程池】带你从0-1入门线程池
|
21天前
|
Java 中间件 调度
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
本文涉及InheritableThreadLocal和TTL,从源码的角度,分别分析它们是怎么实现父子线程传递的。建议先了解ThreadLocal。
56 4
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
|
1月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
100 23
下一篇
oss创建bucket