首页 > 编程语言 >Java四大引用详解:强引用、软引用、弱引用、虚引用

Java四大引用详解:强引用、软引用、弱引用、虚引用

时间:2023-06-23 13:55:50浏览次数:50  
标签:Java Object System 回收 详解 引用 new null

原文链接:https://blog.csdn.net/ChenRui_yz/article/details/126315260

Java引用

从JDK 1.2版本开始,对象的引用被划分为4种级别,从而使程序能更加灵活地控制对象的生命周期,这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

img

强引用

强引用是最普遍的引用,一般把一个对象赋给一个引用变量,这个引用变量就是强引用。

比如:

//  强引用
MikeChen mikechen=new MikeChen();

在一个方法的内部有一个强引用,这个引用保存在Java栈中,而真正的引用内容(MikeChen)保存在Java堆中。

img

如果一个对象具有强引用,垃圾回收器不会回收该对象,当内存空间不足时,JVM 宁愿抛出 OutOfMemoryError异常。

如果强引用对象不使用时,需要弱化从而使GC能够回收,如下:

//帮助垃圾收集器回收此对象
mikechen=null;

显式地设置mikechen对象为null,或让其超出对象的生命周期范围,则GC认为该对象不存在引用,这时就可以回收这个对象,具体什么时候收集这要取决于GC算法

举例:

package com.mikechen.java.refenence;
 
/**
* 强引用举例
*
* @author mikechen
*/
public class StrongRefenenceDemo {
 
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = o1;
        o1 = null;
        System.gc();
        System.out.println(o1);  //null
        System.out.println(o2);  //java.lang.Object@2503dbd3
    }
}

StrongRefenenceDemo 中尽管 o1已经被回收,但是 o2 强引用 o1,一直存在,所以不会被GC回收。

软引用

软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference 类来实现。

比如:

String str=new String("abc");                                     // 强引用
SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。

先通过一个例子来了解一下软引用:

/**
* 弱引用举例
*
* @author mikechen
*/
Object obj = new Object();
SoftReference softRef = new SoftReference<Object>(obj);//删除强引用
obj = null;//调用gc
 
// 对象依然存在
System.gc();System.out.println("gc之后的值:" + softRef.get());

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
SoftReference softRef = new SoftReference<Object>(obj,queue);//删除强引用
obj = null;//调用gc
System.gc();
System.out.println("gc之后的值: " + softRef.get()); // 对象依然存在
//申请较大内存使内存空间使用率达到阈值,强迫gc
byte[] bytes = new byte[100 * 1024 * 1024];//如果obj被回收,则软引用会进入引用队列
Reference<?> reference = queue.remove();if (reference != null){
    System.out.println("对象已被回收: "+ reference.get());  // 对象为null
}

软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收。

我们看下 Mybatis 缓存类 SoftCache 用到的软引用:

public Object getObject(Object key) {
    Object result = null;
    SoftReference<Object> softReference = (SoftReference)this.delegate.getObject(key);
    if (softReference != null) {
        result = softReference.get();
        if (result == null) {
            this.delegate.removeObject(key);
        } else {
            synchronized(this.hardLinksToAvoidGarbageCollection) {
                this.hardLinksToAvoidGarbageCollection.addFirst(result);
                if (this.hardLinksToAvoidGarbageCollection.size() > this.numberOfHardLinks) {
                    this.hardLinksToAvoidGarbageCollection.removeLast();
                }
            }
        }
    }
    return result;}

注意:软引用对象是在jvm内存不够的时候才会被回收,我们调用System.gc()方法只是起通知作用,JVM什么时候扫描回收对象是JVM自己的状态决定的,就算扫描到软引用对象也不一定会回收它,只有内存不够的时候才会回收。

弱引用

弱引用的使用和软引用类似,只是关键字变成了 WeakReference:

MikeChen mikechen = new MikeChen();
WeakReference<MikeChen> wr = new WeakReference<MikeChen>(mikechen );

弱引用的特点是不管内存是否足够,只要发生 GC,都会被回收。

举例说明:

package com.mikechen.java.refenence;
 
import java.lang.ref.WeakReference;
 
/**
* 弱引用
*
* @author mikechen
*/
public class WeakReferenceDemo {
    public static void main(String[] args) {
        Object o1 = new Object();
        WeakReference<Object> w1 = new WeakReference<Object>(o1);
 
        System.out.println(o1);
        System.out.println(w1.get());
 
        o1 = null;
        System.gc();
 
        System.out.println(o1);
        System.out.println(w1.get());
    }
}

弱引用的应用

WeakHashMap

public class WeakHashMapDemo {
 
    public static void main(String[] args) throws InterruptedException {
        myHashMap();
        myWeakHashMap();
    }
 
    public static void myHashMap() {
        HashMap<String, String> map = new HashMap<String, String>();
        String key = new String("k1");
        String value = "v1";
        map.put(key, value);
        System.out.println(map);
 
        key = null;
        System.gc();
 
        System.out.println(map);
    }
 
    public static void myWeakHashMap() throws InterruptedException {
        WeakHashMap<String, String> map = new WeakHashMap<String, String>();
        //String key = "weak";
        // 刚开始写成了上边的代码
        //思考一下,写成上边那样会怎么样? 那可不是引用了
        String key = new String("weak");
        String value = "map";
        map.put(key, value);
        System.out.println(map);
        //去掉强引用
        key = null;
        System.gc();
        Thread.sleep(1000);
        System.out.println(map);
    }}

当key只有弱引用时,GC发现后会自动清理键和值,作为简单的缓存表解决方案。

ThreadLocal

static class ThreadLocalMap {
 
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
 
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    //......}

ThreadLocal.ThreadLocalMap.Entry 继承了弱引用,key为当前线程实例,和WeakHashMap基本相同。

虚引用

虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系。

虚引用需要java.lang.ref.PhantomReference 来实现:

A a = new A();
ReferenceQueue<A> rq = new ReferenceQueue<A>();
PhantomReference<A> prA = new PhantomReference<A>(a, rq);

虚引用主要用来跟踪对象被垃圾回收器回收的活动。

虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

Java引用总结

java4种引用的级别由高到低依次为:强引用 > 软引用 > 弱引用 > 虚引用。

img

以上

标签:Java,Object,System,回收,详解,引用,new,null
From: https://www.cnblogs.com/javaxubo/p/17499065.html

相关文章

  • java当中int类型数据转换为byte类型的数据处理过程
    巨人的肩膀,感谢:https://blog.csdn.net/u013386606/article/details/80526486大前提:目前来说所有数据在内存当中都是以补码的形式存在。原码:原码(trueform)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该......
  • Java基础之基本数据类型封装类的缓存
    巨人的肩膀:https://blog.csdn.net/hnjcxy/article/details/1237872091、Java中基本数据类型byte、short、char、int、long、float、double、boolean有对应的封装类型:Byte、Short、Character、Integer、long、Float、Double,Boolean其中Byte、Short、Character、Integer、Long、Bo......
  • java.util.concurrent.RejectedExecutionException 问题
    java.util.concurrent.RejectedExecutionException问题 http://qingfeng825.iteye.com/blog/1670511 http://blog.sina.com.cn/s/blog_6145ed81010143l8.html http://yaozhiqiang109.iteye.com/blog/1137579......
  • DVWA靶场之CSRF通关详解
    原理CSRF漏洞是指利用受害者尚未失效的身份认证信息(cookie、会话等信息),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下,以受害者的身份向服务器发送请求,从而完成非法操作(如转账、改密、信息修改等操作)。形成原因CSRF的形成原因主要是由于Web应用程序没有......
  • Java打怪升级路线
    第一关:JavaSE阶段1、计算机基础2、java入门学习3、java基础语法4、流程控制和方法5、数组6、面向对象编程7、异常8、常用类9、集合框架10、IO11、多线程12、GUI编程13、网络编程14、注解与反射15、JUC编程16、JVM探究17、23种设计模式18、数据结构与算法19、正......
  • DVWA靶场之XSS通关详解
    原理XSS漏洞是攻击者将恶意代码注入到合法网页中,当用户浏览该页面时,恶意代码会被执行,从而获取用户敏感信息或进行其他攻击。形成原因网站对用户输入数据的过滤不严格或不完备,攻击者可以根据这个漏洞向网站提交恶意代码,然后再将这些代码传播给其他用户,从而造成危害。防御措施......
  • Java 泛型
    泛型GenricsJava泛型是在jdk5引入的新特性。它指定了接收参数的类型,避免了调用者乱传参,保留了代码的通用性和独特性。泛型类和泛型方法一般使用大写字母声明泛型,例如<T>类型擦除Typeerasure思考:能否插入一个字符串元素到一个整型数组中?答案:通过反射是可以的,原理就是类......
  • Java学习-集合篇
    集合什么是集合?有什么用?数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其他类型的数据。集合为什么说在开发中使用的较多?集合是一个容器,是一个载体,可以依次容纳多个对象。在实际的开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程......
  • IntStream的用法详解
    IntStream是一种特殊的Stream,用来提供对int类型数据进行相关的stream操作,下面我们一起来看下。1生成IntStream1.1IntStream.generate用来生成无限个数整数对应的stream,对于需要持续获取随机值的场景可以考虑使用这种方式。publicvoidtestGenerate(){Randomrand......
  • java线程的五种状态
    五种状态开始状态(new)就绪状态(runnable)运行状态(running)阻塞状态(blocked)结束状态(dead)状态变化1、线程刚创建时,是new状态2、线程调用了start()方法后,进入runnable状态,此时并未真正执行,需要和其他线程竞争cpu资源3、当该线程竞争到了cpu资源,进入running状态4、线程因为某种......