配置运行下列代码,显然会报OutOfMemoryError。
/** * 演示软引用 * -Xmx20m */ public class Demo2_3 { private static final int _4MB = 4 * 1024 * 1024; public static void main(String[] args) throws IOException { List<byte[]> list = new ArrayList<>(); for (int i = 0; i < 5; i++) { list.add(new byte[_4MB]); } } }
而以上常见在实际编程中其实是常见的,比如在读取图片内容时。软引用可以解决这种内存占用的问题。
public static void soft() { // list --> SoftReference --> byte[] List<SoftReference<byte[]>> list = new ArrayList<>(); for (int i = 0; i < 5; i++) { SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]); System.out.println(ref.get()); list.add(ref); System.out.println(list.size()); } System.out.println("循环结束:" + list.size()); for (SoftReference<byte[]> ref : list) { System.out.println(ref.get()); } }
以上代码中,list和SoftReference是强引用,但是SoftReference和byte[]是软引用。打印结果如下。
[B@7f31245a 1 [B@6d6f6e28 2 [B@135fbaa4 3 [B@45ee12a7 4 [B@330bedb4 5 循环结束:5 null null null null [B@330bedb4
观察到在循环结束前可以调用到bye[]数组,但是循环结束前四个数组已经变成了null。
添加虚拟机参数:-XX:+PrintGCDetails
-verbose:gc
,打印垃圾回收的细节与详细参数,然后再次运行查看垃圾回收完整过程。
[B@7f31245a 1 [B@6d6f6e28 2 [B@135fbaa4 3 [GC (Allocation Failure) [PSYoungGen: 2209K->488K(6144K)] 14497K->13130K(19968K), 0.0024761 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [B@45ee12a7 4 [GC (Allocation Failure) --[PSYoungGen: 4696K->4696K(6144K)] 17338K->17502K(19968K), 0.0020330 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Ergonomics) [PSYoungGen: 4696K->4466K(6144K)] [ParOldGen: 12806K->12675K(13824K)] 17502K->17142K(19968K), [Metaspace: 3331K->3331K(1056768K)], 0.0100720 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) --[PSYoungGen: 4466K->4466K(6144K)] 17142K->17158K(19968K), 0.0024079 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [Full GC (Allocation Failure) [PSYoungGen: 4466K->0K(6144K)] [ParOldGen: 12691K->740K(8704K)] 17158K->740K(14848K), [Metaspace: 3331K->3331K(1056768K)], 0.0118198 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [B@330bedb4 5 循环结束:5 null null null null [B@330bedb4 Heap PSYoungGen total 6144K, used 4377K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000) eden space 5632K, 77% used [0x00000000ff980000,0x00000000ffdc64f0,0x00000000fff00000) from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) ParOldGen total 8704K, used 740K [0x00000000fec00000, 0x00000000ff480000, 0x00000000ff980000) object space 8704K, 8% used [0x00000000fec00000,0x00000000fecb90f0,0x00000000ff480000) Metaspace used 3352K, capacity 4500K, committed 4864K, reserved 1056768K class space used 359K, capacity 388K, committed 512K, reserved 1048576K
观察到在第三个循环结束后,内存已经快不足,进行了新生代回收。在第四个循环结束后,又进行了一次新生代的回收,但是效果不理想(4696K->4696K),于是触发了一次Full GC。由于进行垃圾回收且内存仍然不足,又触发了一次新的垃圾回收,将软引用所引用的对象释放。像缓存的图片等不重要的对象,可以通过软引用来引用,当内存空间不足时就会回收它们。