正文
● 当发生GC的时候打印GC的简单信息,当程序运行结束打印GC详情
●.
强引用
代码中普遍存在的类似"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象,哪怕是JVM抛出OutOfMemoryError异常,也不会回收内存的,下面看一段代码即可明白
public class GCDemo { private static final int _1MB = 1024 * 1024; private byte[] bytes = new byte[_1MB]; public static void main(String[] args) { test(); } private static void test() { byte[] bytes1 = new byte[5 * _1MB]; byte[] bytes2 = new byte[5 * _1MB]; System.gc(); }}结果如下: [Full GC (System.gc()) [Tenured: 5120K->5120K(10240K), 0.0018258 secs] 10993K->10843K(19456K), [Metaspace: 3090K->3090K(1056768K)], 0.0018492 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Heap par new generation total 9216K, used 6023K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) eden space 8192K, 73% used [0x00000000fec00000, 0x00000000ff1e1db0, 0x00000000ff400000) from space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000) to space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000) tenured generation total 10240K, used 5120K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) the space 10240K, 50% used [0x00000000ff600000, 0x00000000ffb00010, 0x00000000ffb00200, 0x0000000100000000) Metaspace used 3110K, capacity 4494K, committed 4864K, reserved 1056768K class space used 340K, capacity 386K, committed 512K, reserved 1048576K
我们可以看到,即使GC了也没有回收,而且共有10993K内存转移到了老年代了,从10993K->10843K可以判断出并没有回收掉,也就是说
10M的字节没有被回收
,那么我们加大一点测试看看会不会内存错误,
public class GCDemo { private static final int _1MB = 1024 * 1024; private byte[] bytes = new byte[_1MB]; public static void main(String[] args) { test(); } private static void test() { byte[] bytes1 = new byte[5 * _1MB]; byte[] bytes2 = new byte[10* _1MB]; System.gc(); }}可以看到发生错误了,[Full GC (Allocation Failure) [TenuredException in thread "main" java.lang.OutOfMemoryError: Java heap space at Collections.GCDemo.test(GCDemo.java:17) at Collections.GCDemo.main(GCDemo.java:12) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release: 5725K->5700K(10240K), 0.0018018 secs] 5725K->5700K(19456K), [Metaspace: 3042K->3042K(1056768K)], 0.0018229 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Heap par new generation total 9216K, used 322K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
那要怎样释放呢,手动置为null,就失去了GC Roots引用连,这样就可以回收了
public class GCDemo { private static final int _1MB = 1024 * 1024; private byte[] bytes = new byte[_1MB]; public static void main(String[] args) { test(); //System.gc } private static void test() { byte[] bytes1 = new byte[5 * _1MB]; byte[] bytes2 = new byte[5 * _1MB]; bytes1 = null; bytes2 = null; System.gc(); }}[Full GC (System.gc()) [TenuredJava HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release: 5120K->602K(10240K), 0.0018229 secs] 11015K->602K(19456K), [Metaspace: 3069K->3069K(1056768K)], 0.0018489 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] Heap par new generation total 9216K, used 299K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
可以看到从11015K->602K,说明手动置null之后经过了一个gc,那些都被回收了,实际上如果不手动置为null,也可以在方法执行之后再调用System.gc()方法的,这样一样可以回收内存,其原因是test()只是一个方法,当JVM执行完方法返回的时候,会清空当前的栈帧,而测试的是在方法内分配的,自然就会随着方法结束而释放掉内存了,就是注释去掉,然后不用手动置null,是一样的效果来的。