Java中的软引用,你了解吗?

2023-11-21 11:40:08 浏览数 (1)


theme: healer-readable

highlight: a11y-dark


哈喽,各位小伙伴们,你们好呀,我是喵手。

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在Java中,垃圾回收是一个非常重要的概念。为了防止内存泄漏和程序的性能问题,Java中对于对象的垃圾回收进行了优化和改进。其中,软引用就是垃圾回收的一种方式。本文将介绍Java中的软引用,其基本概念以及如何在实际应用中使用软引用

摘要

本文将深入探讨Java中的软引用,包括其定义和使用。我们将介绍如何使用软引用来避免内存泄漏和优化程序性能。本文还将提供源代码解析,应用场景案例以及优缺点分析,以便读者更好地理解软引用的特点和使用方法。

软引用

简介

在Java中,垃圾回收是一种自动化的内存管理机制。Java垃圾回收器会自动查找不再使用的对象并将其释放回内存供重用。软引用是Java中一种机制,用于保留对对象的引用,但允许该对象被垃圾回收器回收。软引用可以帮助程序员更精细地控制内存的使用,节省程序资源并提高程序性能。

软引用对象可以通过java.lang.ref.SoftReference类创建。SoftReference对象允许程序员保留对对象的引用,但允许该对象被垃圾回收器回收。当Java虚拟机需要内存时,垃圾回收器将会回收由软引用指向的对象。软引用可以用于缓存,使得垃圾回收器在内存不足时可以回收该对象,从而避免内存泄漏。

源代码解析

下面是一个简单的Java代码例子,演示如何使用软引用:

代码语言:java复制
import java.lang.ref.SoftReference;

public class SoftReferenceExample {
    public static void main(String[] args) {
        Object obj = new Object();
        SoftReference<Object> softRef = new SoftReference<Object>(obj);
        obj = null;
        System.gc();
        if (softRef.get() != null) {
            System.out.println("Object is still available");
        } else {
            System.out.println("Object has been collected");
        }
    }
}

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

  1. 创建一个Object对象,然后创建一个SoftReference对象来引用该Object对象。
  2. obj变量赋一个null值,这表示原来的Object对象已经没有指向它的引用了,只有软引用对象持有它的引用。
  3. 调用System.gc()方法,手动通知垃圾回收器回收不再使用的对象。
  4. 如果软引用对象的get()方法返回null,表示原来的Object对象已经被回收;否则,表示原来的Object对象仍然可用。

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

在这里插入图片描述在这里插入图片描述

应用场景案例

软引用可以用于缓存、图片处理等方面,以避免内存泄漏和优化程序性能。下面是两个Java使用软引用的实际案例:

缓存

在Java中,缓存是一种常见的性能优化技术。使用软引用可以避免缓存对象过多占用内存。当内存不足时,垃圾回收器将会回收软引用指向的对象。下面是一个简单的缓存实现:

代码语言:java复制
package com.example.javase.se.classes.softReference;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author ms
 * @Date 2023-11-05 21:52
 */
public class Cache {

    private Map<String, SoftReference<Object>> cacheMap;

    public Cache() {
        this.cacheMap = new HashMap<String, SoftReference<Object>>();
    }

    public void put(String key, Object value) {
        cacheMap.put(key, new SoftReference<Object>(value));
    }

    public Object get(String key) {
        Object obj = null;
        SoftReference<Object> softRef = cacheMap.get(key);
        if (softRef != null) {
            obj = softRef.get();
        }
        return obj;
    }

    public void clear() {
        cacheMap.clear();
    }
}

说明:

  1. 构造方法创建一个Map对象,用于存储软引用对象。
  2. put()方法将软引用对象添加到Map对象中。
  3. get()方法从Map对象中获取软引用对象,通过get()方法获取原始对象。
  4. clear()方法清空Map对象。

图片处理

在Java中,处理大量图片可能会导致内存泄漏和程序性能低下。使用软引用可以避免占用过多的内存,并提高程序性能。下面是一个简单的Java代码例子,演示如何使用软引用来缓存图片:

代码语言:java复制
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import javax.imageio.ImageIO;

public class ImageCache {
    private static final String IMAGE_DIR = "images/";
    private static Map<String, SoftReference<BufferedImage>> imageCache = new HashMap<String, SoftReference<BufferedImage>>();
    public static BufferedImage getImage(String fileName) {
        SoftReference<BufferedImage> soft = imageCache.get(fileName);
        if (soft != null) {
            BufferedImage image = soft.get();
            if (image != null) {
                return image;
            }
        }
        File file = new File(IMAGE_DIR   fileName);
        try {
            BufferedImage image = ImageIO.read(file);
            imageCache.put(fileName, new SoftReference<BufferedImage>(image));
            return image;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

说明:

  1. getImage()方法从imageCache中获取指定文件名对应的图像。如果软引用对象存在,就从软引用中获取BufferedImage对象;否则,就从磁盘中读取图像。
  2. 当软引用对象被回收时,JVM将自动从磁盘中读取图像。

优缺点分析

软引用的优点:

  1. 对象可以被垃圾回收器回收,避免内存泄漏。
  2. 可以用于缓存、图片处理等方面,以优化程序性能。
  3. 不会影响程序的正常运行。

软引用的缺点:

  1. 对象的生命周期难以控制,容易被回收。
  2. 软引用对象不能被强制保留,可能会造成性能问题。
  3. 对象被回收后,重新获取时可能会影响程序性能。

类代码方法介绍

java.lang.ref.SoftReference类

代码语言:java复制
public class SoftReference<T> extends Reference<T>

该类继承自Reference类,用于创建软引用对象。可以在Java中使用该类来实现软引用。

方法:

  1. get():返回由此软引用对象所引用的对象。

Cache类

代码语言:java复制
public class Cache {
    private Map<String, SoftReference<Object>> cacheMap;
    public Cache();
    public void put(String key, Object value);
    public Object get(String key);
    public void clear();
}

说明:

  1. 构造方法用于创建Cache对象,并创建一个Map对象,用于存储软引用对象。
  2. put()方法将软引用对象添加到Map对象中。
  3. get()方法从Map对象中获取软引用对象,通过get()方法获取原始对象。
  4. clear()方法清空Map对象。

ImageCache类

代码语言:java复制
public class ImageCache {
    private static final String IMAGE_DIR = "images/";
    private static Map<String, SoftReference<BufferedImage>> imageCache = new HashMap<String, SoftReference<BufferedImage>>();
    public static BufferedImage getImage(String fileName);
}

说明:

  1. getImage()方法从imageCache中获取指定文件名对应的图像。如果软引用对象存在,就从软引用中获取BufferedImage对象;否则,就从磁盘中读取图像。

测试用例

下面是一个简单的测试用例,演示如何使用软引用来避免内存泄漏和优化程序性能:

代码语言:java复制
public class TestSoftReference {

    public static void main(String[] args) {
        // 创建一个字符串对象并赋值"hello"
        String str = new String("hello");
        // 创建一个软引用,指向该字符串对象
        SoftReference<String> softRef = new SoftReference<String>(str);
        // 将原字符串对象引用置为null
        str = null;
        // 手动触发垃圾回收
        System.gc();
        // 判断软引用是否还指向对象
        if (softRef.get() != null) {
            System.out.println("软引用对象未被回收,内容为:"   softRef.get());
        } else {
            System.out.println("软引用对象已被回收");
        }
    }

}

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

运行结果:

代码语言:java复制
软引用对象未被回收,内容为:hello
在这里插入图片描述在这里插入图片描述

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

这段代码演示了软引用的基本用法。首先创建了一个字符串对象并赋值"hello",然后创建一个软引用 softRef,指向该字符串对象。接着将原字符串对象 str 引用置为 null,这是为了让该对象成为垃圾对象。然后手动触发垃圾回收,这会触发 JVM 进行垃圾回收。

最后判断软引用是否还指向对象。如果 softRef.get() 不为 null,则说明软引用对象未被回收,打印 "软引用对象未被回收,内容为:" softRef.get(),内容为 hello;否则说明软引用对象已被回收,打印 "软引用对象已被回收"。

可以通过改变 JVM 参数来观察软引用对象的回收情况。

SoftReference 是 JVM 提供的一种基本的引用类型,在内存充足时表现和普通强引用一样,但在内存不足时,会被 GC 回收,避免 OutOfMemoryError 异常。

继续看下一个测试用例,这次我们将创建一个缓存类来存储软引用对象:

代码语言:java复制
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

public class Cache {

    private Map<String, SoftReference<Object>> cacheMap;

    public Cache() {
        cacheMap = new HashMap<>();
    }

    public void put(String key, Object value) {
        SoftReference<Object> softRef = new SoftReference<Object>(value);
        cacheMap.put(key, softRef);
    }

    public Object get(String key) {
        SoftReference<Object> softRef = cacheMap.get(key);
        if (softRef != null) {
            return softRef.get();
        }
        return null;
    }

    public void clear() {
        cacheMap.clear();
    }

}

该缓存类的实现很简单,使用Map来存储软引用对象,put()方法用于添加软引用对象,get()方法用于获取原始对象,clear()方法用于清空缓存。接下来,我们来测试该缓存类的使用:

代码语言:java复制
public class TestCache {

    public static void main(String[] args) {
        // 创建一个缓存对象
        Cache cache = new Cache();
        // 缓存一个字符串对象
        String str = new String("hello");
        cache.put("str", str);
        // 将原字符串对象引用置为null
        str = null;
        // 手动触发垃圾回收
        System.gc();
        // 从缓存中获取字符串对象
        String cacheStr = (String) cache.get("str");
        // 判断缓存对象是否为空
        if (cacheStr != null) {
            System.out.println("从缓存中获取到对象:"   cacheStr);
        } else {
            System.out.println("缓存中不存在该对象");
        }
    }

}

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

运行结果:

代码语言:java复制
从缓存中获取到对象:hello
在这里插入图片描述在这里插入图片描述

在这个示例中,我们使用Cache类来缓存一个字符串对象,并将原字符串对象的引用置为null,手动触发垃圾回收。接着,从缓存中获取字符串对象,判断缓存对象是否为空。由于该缓存对象仍然指向该字符串对象,所以从缓存中成功获取到了该对象。

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

该程序演示了使用软引用实现缓存功能。主要流程如下:

  1. 创建一个 Cache 对象,用于缓存对象。
  2. 创建一个字符串对象 "hello",并调用 Cache 对象的 put 方法将其保存到缓存中。
  3. 将字符串对象的引用 str 置为 null。
  4. 手动触发垃圾回收,此时会触发软引用对象的回收。
  5. 从缓存中获取字符串对象并赋值给变量 cacheStr。
  6. 判断 cacheStr 是否为空,如果不为空则表示从缓存中获取到了字符串对象。

因为字符串对象被缓存后,只有缓存对象持有其软引用,当内存不足时,垃圾回收器会根据对象的引用类型及其占用内存的大小来进行垃圾回收。软引用可以在内存不足时被垃圾回收器回收,但要避免在内存足够的时候就被回收,否则就失去了缓存的意义。因此,这种方式适合缓存占用内存比较大、但不需要长时间保存的对象。

小结

软引用是Java中一种垃圾回收的方式,可以用于避免内存泄漏和优化程序性能。在Java中,可以通过SoftReference类来创建软引用对象,并可用于缓存、图片处理等方面。使用软引用可以更精细地控制内存的使用,避免内存泄漏和提高程序性能。在使用软引用时,需要注意对象的生命周期和软引用对象是否被回收。

总结

本文介绍了Java中的软引用,包括其定义、源代码解析、应用场景案例和优缺点分析。软引用是一种垃圾回收的方式,可以保留对对象的引用,但允许该对象被垃圾回收器回收,避免内存泄漏和优化程序性能。可以使用java.lang.ref.SoftReference类来创建软引用对象,并可用于缓存、图片处理等方面。需要注意对象的生命周期和软引用对象是否被回收,以便更好地控制内存的使用。

... ...

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞