上一篇文章我们讲解了 什么是jvm垃圾,什么样的对象才会被称为垃圾 会被回收, 顺便讲到了 引用关系,今天我们介绍一下第二种引用关系 软引用
通过SoftReference引用对象时,这个引用就是软引用。软引用是还有点用,但是并不是必须的对象
在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收, 如果第二次回收还没有足够的内存,就会抛出内存溢出异常。
软引用自身也是一个对象(SoftReference类型的对象),也会占用内存空间, Java中的软引用是通过 SoftReference类来实现的
设置JVM参数
-verbose:gc -Xmx10M -Xms10M -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
创建一个 FinalObj对象
public class MyFinalObj {
//一般开发中不用调用这个方法
@Override
protected void finalize() throws Throwable {
System.out.println(Thread.currentThread().getName() + "\t" + "---方法调用 finalize ....");
}
}
新建Test类, 类中手动触发 System.gc();
@Slf4j
public class JvmSoftTest {
public static void main(String[] args) throws Exception {
SoftReference soft = new SoftReference<>(new MyFinalObj());
log.info("gc 前 内存充足=======" + soft.get());
//手动触发 gc
System.gc();
Thread.sleep(1000);
log.info("gc 后 内存充足=======" + soft.get());
}
}
执行,打印日志如下:
[GC (Allocation Failure) [PSYoungGen: 2048K->512K(2560K)] 2048K->728K(9728K), 0.0010054 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2560K->512K(2560K)] 2776K->1006K(9728K), 0.0012670 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2557K->512K(2560K)] 3051K->1450K(9728K), 0.0008688 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
21:32:10.808 [main] INFO com.jzj.tdmybatis.util.JvmSoftTest - gc 前 内存充足=======com.jzj.tdmybatis.util.MyFinalObj@5d6f64b1
[GC (System.gc()) [PSYoungGen: 1493K->512K(2560K)] 2431K->1682K(9728K), 0.0013372 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 512K->0K(2560K)] [ParOldGen: 1170K->1255K(7168K)] 1682K->1255K(9728K), [Metaspace: 4744K->4744K(1056768K)], 0.0105563 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
21:32:11.827 [main] INFO com.jzj.tdmybatis.util.JvmSoftTest - gc 后 内存充足=======com.jzj.tdmybatis.util.MyFinalObj@5d6f64b1
Heap
PSYoungGen total 2560K, used 595K [0x00000007bfd00000, 0x00000007c0000000, 0x00000007c0000000)
eden space 2048K, 29% used [0x00000007bfd00000,0x00000007bfd94f90,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
to space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
ParOldGen total 7168K, used 1255K [0x00000007bf600000, 0x00000007bfd00000, 0x00000007bfd00000)
object space 7168K, 17% used [0x00000007bf600000,0x00000007bf739ff0,0x00000007bfd00000)
Metaspace used 4851K, capacity 5068K, committed 5248K, reserved 1056768K
class space used 538K, capacity 564K, committed 640K, reserved 1048576K
可以看到 触发gc后 对象依旧存在, 所以说 软引用的对象 在内存充足的时候是不会被回收的
现在我们相同的方法 创建软引用对象, 然后 根据 jvm设置的 内存大小, 创建一个比较大的对象8M, 占满内存, 然后看看 软引用的对象是否会被 gc回收
public static void main(String[] args) throws Exception {
//设置JVM参数 -Xms10M -Xmx10M
SoftReference soft = new SoftReference<>(new MyFinalObj());
log.info("gc 前 内存充足=======" + soft.get());
try {
log.info("gc 前 创建8M大对象 =======" );
byte[] bytes = new byte[8 * 1024 * 1024];
}catch (Exception e){
e.printStackTrace();
}finally {
log.info("gc 后 内存溢出 =======" + soft.get());
}
}
执行,打印日志如下:
21:45:24.131 [main] INFO com.jzj.tdmybatis.util.JvmSoftTest - gc 前 内存充足=======com.jzj.tdmybatis.util.MyFinalObj@5d6f64b1
21:45:24.134 [main] INFO com.jzj.tdmybatis.util.JvmSoftTest - gc 前 创建8M大对象 =======
[GC (Allocation Failure) [PSYoungGen: 1477K->480K(2560K)] 2437K->1679K(9728K), 0.0013545 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 480K->480K(2560K)] 1679K->1687K(9728K), 0.0011450 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 480K->0K(2560K)] [ParOldGen: 1207K->1256K(7168K)] 1687K->1256K(9728K), [Metaspace: 4738K->4738K(1056768K)], 0.0083094 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 1256K->1256K(8704K), 0.0011856 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 1256K->1181K(7168K)] 1256K->1181K(8704K), [Metaspace: 4738K->4738K(1056768K)], 0.0085159 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid23687.hprof ...
Finalizer ---方法调用 finalize ....
Heap dump file created [2325085 bytes in 0.010 secs]
21:45:24.165 [main] INFO com.jzj.tdmybatis.util.JvmSoftTest - gc 后 内存溢出 =======null
内存敏感的数据缓存机制,如图片、网页缓存, 实际项目中对于存储图片资源这些并不是很重要的内容时并且内存资源十分紧张,我们可以使用软引用来进行。
系统加载的时候把图片及缓存处理好, 系统一旦资源不足, 就会把这块内存回收, 不会影响性能, 当系统资源充足的时候, 软引用的一直存在, 可以直接取用, 方便快捷
本文我们讲述了 软引用的使用方法及适用场景, 以及软引用对象的垃圾回收机制,便于我们在实际的项目中进行软引用的实战