美文网首页我爱编程
JVM:垃圾收集器与内存分配策略(上)

JVM:垃圾收集器与内存分配策略(上)

作者: renyjenny | 来源:发表于2018-06-21 22:15 被阅读0次

    概述

    要研究的问题

    • 回收哪些内存
    • 什么时候回收
    • 如何回收

    为什么要了解GC和内存分配:需要排查各种内存溢出、内存泄露的问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,就需要对这些“自动化”的技术实施必要的监控和调节。
    需要回收的区域:程序计数器、虚拟机栈、本地方法栈三个区域是线程私有的,其生命周期和拥有它们的线程的生命周期一致,其内存分配和回收都具有确定性,所以不需要进行讨论。Java堆和方法区这两个区域,要在程序运行时才能确定下来,其内存分配和回收都是动态的,是垃圾回收的关注区域。

    对象存活判断

    不会再被使用的对象就是不再存活的对象,其存活的判断有以下两种算法。

    引用计数算法

    给对象添加一个引用计数器,每当有一个地方引用它时,计数器加1,当它失去一个引用时,计数器减1。当计数器为0时,则表示该对象已死。
    缺点:无法解决对象间循环互相引用的问题。


    引用计数算法.png

    途中对象objA和objB现在分别被引用,其中objA中的instance字段引用着objB,objB也是如此。按照引用计数算法,它们的计数器都为2。此时令objA=null,objB=null,它们的计数器分别为1。事实上这两个对象都不会再被使用了,但因为它们彼此引用着,将永远不会被回收。

    可达性分析算法

    以“GC Roots”对象作为起点往下搜索,搜索走过的路径称为引用链(Reference Chain)。如果一个对象没有与GC Roots没有引用链相连,那这个对象是不可用的,将会被回收。
    可以称为GC Roots的对象:

    • 虚拟机栈(栈帧中的本地变量表)中引用的对象
    • 方法区中类静态属性引用的对象
    • 方法区中常量引用的对象
    • 本地方法栈中JNI(Native方法)引用的对象


      可达性分析算法.png

    引用分类

    • 强引用:类似“Object obj = new Object()”创建的对象,只要强引用还存在,对象永远不会被回收。
    • 软引用:一些还有用但并非必须的对象。当内存空间快要不够用时会回收这些对象。可通过SoftReference类实现。
    • 弱引用:只能存活到下一次垃圾收集之前的对象。可通过WeekReference类实现。
    • 虚引用:虚引用是否存在对其引用的对象的生存时间没有任何影响,也无法通过虚引用取得对象实例。设置虚引用的唯一目的是在这个对象被收集器回收时收到一个系统通知。可通过PhantomRefence类实现。

    回收经过

    对象回收.png

    对象的Finalize()方法只会被系统自动调用一次(对象只会有一次自救的机会)。
    不建议在finalize()方法中自救,事实上,在JDK9中finalize方法已经被标记为deprecated。

    方法区回收

    回收内容:废弃常量和无用的类。
    常量废弃判断:与对象存活判断相似,当常量没有被引用后就可以废弃。
    类无用判断:

    • 该类的所有实例都被回收
    • 加载该类的ClassLoader已经被回收
    • 该类对应的java.lang.Class对象在任何地方都没有被引用,也无法在任何地方通过反射访问该类的方法

    垃圾收集方法

    标记-清理算法

    如回收经过过,对象经过两次标记后再回收。首先将需要回收的对象标记,再一次清理。
    缺点:

    • 效率问题:标记和清理的效率都不高。
    • 空间问题:清理后会产生大量不连续的内存碎片


      标记-清理.png

    复制算法

    将可用内存按容量划分为大小相同的两块,每次只在一块上分配内存,另一块保留。可分配块的内存用完了,就将存活的对象复制到保留区,再清空可分配区,之后,可分配区与保留区对换。
    优点:实现简单、运行高效,不用再考虑内存碎片的问题,分配内存只需移动内存指针。
    缺点:每次只能使用一半内存,性能不高。


    复制算法.png

    目前的商业虚拟机均采取此种方式进行垃圾回收,但保留区与分配区并不是1:1划分的。将内存分为一块较大的Eden空间和两块较小的Survivor空间,比例为8:1:1。因为新生代中的对象,98%属于“朝生夕死”的,所以清理后还剩下的对象,移到其中一块Survivor上已经足够了。新生代中的可用内存空间为整个新生代容量的90%,只有10%作为保留区。

    标记-整理算法

    标记-清理算法的升级版,标记后将存活的内存移到内存的一端去,再将其他的清理掉。
    优点:避免了内存碎片的产生。
    缺点:效率不高。


    标记-整理.png

    分代收集算法

    根据对象存活周期的不同,将内存划分为几块,如新生代和老年代。新生代中的对象存活率低,每次收集后仅有少部分存活,可以使用复制算法。老年代中对象存活率高,且没有额外空间对它进行分配担保,所以使用标记-清理或标记-整理算法。

    相关文章

      网友评论

        本文标题:JVM:垃圾收集器与内存分配策略(上)

        本文链接:https://www.haomeiwen.com/subject/mioreftx.html