前言
在 Java中的各种引用(强引用、软引用、弱引用、虚引用)(一)里面已经说过了对象的创建和内存的分布,也提到了四种引用,这里说一下强引用。
强引用
强引用就是一般的对象引用。被强引用的对象,只有在完全没有任何引用的时候,才会被系统回收。只要该对象存在引用,系统宁可抛出OOM,也不会强制回收该对象。
举例
准备
首先,需要对JVM的运行环境做一下设置,我们可以设置JVM的内存为20M,以方便观察。
-Xms20M -Xmx20M
测试
package com.test.application;
public class StrongReferences {
public static void main(String[] args) throws InterruptedException {
//Create a byte array, size is 13M
byte[] big1 = new byte[13 * 1024 * 1024];
System.out.println(System.currentTimeMillis() + ": " + big1);
//Start the gc and wait 1s
System.gc();
Thread.sleep(1000);
System.out.println(System.currentTimeMillis() + ": " + big1);
//Create another byte array, size is 7M
byte[] big2 = new byte[7 * 1024 * 1024];
System.out.println(System.currentTimeMillis() + ": " + big2);
}
}
输出结果:
1603957724013: [B@140e19d
1603957725021: [B@140e19d
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.test.application.StrongReferences.main(StrongReferences.java:14)
从结果可以看出,尽管触发了GC,但是内存空间并没有释放。如果需要释放,需要将big1的引用对象置为null(是否在GC前后没有关系,JVM有自己的垃圾回收,**System.gc()**只是强制触发一次垃圾回收)。
说明
在JVM参数中添加**-XX:+PrintGC**,可以查看JVM内存的垃圾回收日志信息。
-Xms20M -Xmx20M -XX:+PrintGC
运行结果:
1603957755744: [B@140e19d
[GC (System.gc()) 14989K->14028K(19712K), 0.0008208 secs]
[Full GC (System.gc()) 14028K->13937K(19712K), 0.0042578 secs]
1603957756750: [B@140e19d
[Full GC (Ergonomics) 14270K->13967K(19712K), 0.0038843 secs]
[Full GC (Allocation Failure) 13967K->13952K(19712K), 0.0035177 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.test.application.StrongReferences.main(StrongReferences.java:14)
可以看到,当创建对象 new byte[7 * 1024 * 1024] 的时候,JVM已经没有足够的内存了。此时,对于第一个对象new byte[13 * 1024 * 1024] ,仍然存在内存中,没有被回收掉。此时,JVM只能抛出OOM异常。
添加一个将big1的指向置为null的操作后,在查看运行结果
···
System.gc();
big1 = null;
Thread.sleep(1000);
···
运行结果:
1603958096674: [B@140e19d
[GC (System.gc()) 14876K->14076K(19712K), 0.0008062 secs]
[Full GC (System.gc()) 14076K->13936K(19712K), 0.0051718 secs]
1603958097681: null
[Full GC (Ergonomics) 14243K->655K(19712K), 0.0054385 secs]
1603958097687: [B@17327b6
big1置为null之后,对象new byte[13 * 1024 * 1024] 失去所有引用,此时,被回收,JVM有足够的内存空间来创建对象 new byte[7 * 1024 * 1024] 。
结论
强引用是最常见的引用,但是对内存的需求很大。当存在太多的强引用对象时,JVM可能会抛出OOM异常。在实际的使用中,建议对已经使用结束的引用做null处理,以减少对内存的占用。