转载

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

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

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

模拟 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

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

可见最大的对象是Finalizer类

查看 Finalizers 队列

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

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

原文  http://mousycoder.com/thinking-in-jvm/38/
正文到此结束
Loading...