• Java Finalization‘s Memory-Retention Issues 及Reference类解析


    引言

    《Effective Java Programming Language Guide》 一书中强烈建议不要使用java的finalize()方法去做对象消亡前的清理。因为jvm调用finalize()方法的时机并不确定,容易导致Memory-Retention Issues。通俗点讲就是内存没办法及时回收。
    详细的见oracle的官方说明https://www.oracle.com/technical-resources/articles/javase/finalization.html。

    Memory-Retention Issues问题简述

    如果类有重写finalize()方法,JVM会将该类的对象标记为finalizable,区别于普通对象被垃圾收集器判定为不可达时,会立即回收内存,finalizable的对象会经过更多的GC周期。
    下图来自oracle官方。
    在这里插入图片描述
    finalizable对象回收通常经历以下过程

    1. 垃圾回收器检查到该对象不可达
    2. 垃圾回收器将该对象加入到finalization队列,对象变成可达
    3. 专门的Finalizer线程从finalization队列中将对象移除,并执行对象的finalize()方法,并将对象标记为finalized
    4. 垃圾回收器再次发现该对象不可达,而且为finalized状态的(finalize方法已执行过),因此直接回收该对象内存。

    以上过程的一些个人分析:

    jvm为什么不直接在回收对象前调用finalize()方法,而是使用专门的线程去执行

    java每次GC需要通过可达性分析标记大量对象,回收内存后,还涉及内存整理,如果把finalize()方法的调用也放到这个过程中,GC耗时会更长,影响系统的响应时间,所以只能由另外的过程去处理。

    Memory-Retention问题

    从上述过程可以看到,finalizable对象至少要2个GC周期才能将对象回收掉。更有甚者,如果系统中有大量的对象是finalizable,或者有些对象finalize()方法本身就比较耗时,加上只有一个Finalizer线程,这个线程优先级并不比别的高,还会和其他线程竞争执行资源,对象在finalization队列中呆的时间更长。在这期间如果有发生GC,垃圾收集器也是无法清理这些对象的,因此这些对象还在被finalization队列强引用。所以容易产生Memory-Retention问题。

    Memory-Retention问题解决方案

    《Effective Java Programming Language Guide》建议使用JDK的Cleaner来做对象消亡前的清理,其基于PhantomReference,下面系统的介绍JDK的Reference。

    Reference解析

    java的Reference的相关子类,用于应用层与垃圾收集器有更多的交互,通俗点讲就是垃圾收集器给应用层暴露一些API,让应用对对象的回收时机有了一定的控制能力。

    SoftReference

    垃圾回收器会根据内存使用情况对软引用对象进行回收,当然jvm会尽可能的不回收软引用对象,至于什么情况下回收,JDK并没有明确说明。根据其特点可以看出SoftReference可以用于缓存设计缓存,这样不用自己去设计LRU等算法对缓存进行清理。
    一旦垃圾收集器认为软引用对象需要被清理时,JVM会解除软引用对对象的引用(即将referent字段置为null),同时或者稍后将软引用自己放到ReferenceQueue(如果创建软引用时有传入)
    JDK保证在jvm抛出OutOfMemoryError前,清掉所有的软引用对象。除此之外,并不保证软引用对象被清理的时间点,而且也不保证软引用对象清理的顺序。

    WeakReference

    一旦垃圾回收器检测到对象只有弱引用,会立即解除弱引用(将弱引用的referent字段置为null),同时或者稍后将弱引用放入ReferenceQueue(如果创建软引用时有传入)。
    弱引用不能阻止垃圾回收器对对象的回收,因此弱引用一般用于“规范化映射(canonicalizing mappings)”,例如WeakHashMap。
    对canonicalizing mappings详细说明可以阅读
    https://objectcomputing.com/resources/publications/sett/june-2000-collaborating-with-the-java-memory-manager
    https://wiki.c2.com/?CanonicalizedMapping

    PhantomReference

    虚引用在垃圾回收器确定其引用对象可以被回收后放到ReferenceQueue,这一点与SoftReference及WeakReference有所区别。对于finalizable对象,后两者在垃圾回收器将对象放入finalization队列时,就会解除引用并将引用放入到ReferenceQueue。而PhantomReference必须在finalizable对象从finalization队列移除后,并且被垃圾回收器再次检测到不可达能够真正的回收其内存时,放入到ReferenceQueue中,而且引用不会自动解除。
    在这里插入图片描述

    未完待续

  • 相关阅读:
    Jquery版轮播图超详细
    Linux权限有哪些
    Qt5.14.2在Windows下使用mysql
    你必须知道的6个免费图片素材网站
    旅拍摄影技巧&澳大利亚、韩国旅行攻略
    Linux内存管理(二十五):slub 分配器之kmem_cache_destroy
    静态链接库与动态链接库
    nginx核心板块来构建静态服务器三
    简述三范式
    操作系统——程序地址空间
  • 原文地址:https://blog.csdn.net/shuxiaohua/article/details/134543289