finalize()是由 FinalizerThread 线程处理的,每一个即将被回收的并且包含 finalize() 方法的对象都会在正式回收前加入到 FinalizerThread 的执行队列,其中该队列强引用着实际的对象,如果引用队列在执行 finalize()方法出现了性能问题,会导致这些垃圾对象长时间占用内存,导致 OOM
finalize()方法中sleep增加耗时
package com.mousycoder.mycode.thinking_in_jvm; /** * @version 1.0 * @author: mousycoder * @date: 2019-07-16 16:31 */ public class LongFinalize { public static class LF { private byte[] content = new byte[512]; @Override protected void finalize() throws Throwable { try { System.out.println(Thread.currentThread().getId()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { long b = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { LF f = new LF(); } long e = System.currentTimeMillis(); System.out.println(e - b); } }
虚拟机参数
-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
输出
Exception in thread "main" [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7167K(7168K)] 9215K->9215K(9728K), [Metaspace: 2748K->2748K(1056768K)], 0.0042960 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7167K(7168K)] 9215K->9215K(9728K), [Metaspace: 2761K->2761K(1056768K)], 0.0052910 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [Full GC (Allocation Failure) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7167K(7168K)] 9215K->9215K(9728K), [Metaspace: 2761K->2761K(1056768K)], 0.0080970 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main" [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7166K(7168K)] 9215K->9214K(9728K), [Metaspace: 2761K->2761K(1056768K)], 0.0085330 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] Heap PSYoungGen total 2560K, used 2047K [0x00000007bfd00000, 0x00000007c0000000, 0x00000007c0000000) eden space 2048K, 99% used [0x00000007bfd00000,0x00000007bfeffff8,0x00000007bff00000) from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000) to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000) ParOldGen total 7168K, used 7167K [0x00000007bf600000, 0x00000007bfd00000, 0x00000007bfd00000) object space 7168K, 99% used [0x00000007bf600000,0x00000007bfcffcf8,0x00000007bfd00000) Metaspace used 2767K, capacity 4486K, committed 4864K, reserved 1056768K class space used 300K, capacity 386K, committed 512K, reserved 1048576K
可见新生代、老年代都被垃圾占满了,才导致的 OOM,这些本该被回收,可是 finalize()中耗时方法,导致对象长时间被 Finalizer 引用,而得不到释放。
可见最大的对象是Finalizer类
查看 Finalizers 队列
去掉finalize()耗时方法,则程序很快正常结束,则可以说明 finalize()对 GC 的影响