【深入浅出-JVM】(38):Finalize

finalize()是由 FinalizerThread 线程处理的,每一个即将被回收的并且包含 finalize() 方法的对象都会在正式回收前加入到 FinalizerThread 的执行队列,其中该队列强引用着实际的对象,如果引用队列在执行 finalize()方法出现了性能问题,会导致这些垃圾对象长时间占用内存,导致 OOM

模拟 finalize() 出现性能问题对回收影响

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 引用,而得不到释放。

MAT 分析Dump

可见最大的对象是Finalizer类

查看 Finalizers 队列

去掉finalize()耗时方法,则程序很快正常结束,则可以说明 finalize()对 GC 的影响

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章