zoukankan      html  css  js  c++  java
  • JVM学习总结二——垃圾回收算法

        昨天总结了JVM内存分区相关的知识,这次我们将来了解下JVM的另一个核心知识点——垃圾回收算法。这一部分其实并不太难,如果对操作系统的内存处理算法有所了解,那么这部分算法其实只看名字就能明白,两者在原理上是一样的,而且JVM的相对更为简单点。

        在初学JVM的时候,我们往往会对这部分感到迷惑:网上不少博客介绍的五花八门,像引用计数算法、串行、并行、并发算法等,他们到底算不算垃圾回收算法,算的话又和基本的那几个算法有什么关系呢?(PS:其实如果认真看过书的话,就不会疑惑了,因为书里边介绍的很清晰),下边我们来理一下这些算法的关系:

    • 对象存活判断算法:引用计数、可达性分析
    • 基本的垃圾回收算法:标记-清除、复制、标记-整理
    • 依赖线程实现的回收算法:串行、并行、并发

        其中对象存活判定算法是其他算法的基石,用来判断对象是否存活,能否回收;基本的垃圾回收算法是垃圾垃圾收集器实现的基础算法;而依赖线程实现的算法,则是基本算法在考虑线程环境下的运用,这个有多线程基础的看名字就明白了。此外,还有综合以上算法并从特定角度实现的算法,如分代回收(针对分区)、增量回收(针对实时性)等,在此不再介绍

    一、对象存活判断算法

       在我们回收一个对象之前,我们首先要搞明白的一点是这个对象是不是已经死了(没有用了),而对于java程序而言,当一个对象不再被引用,那么他就死了(没被引用就无法被正常访问了)。为实现这个判断,可以使用两种算法实现:引用计数可达性分析
        引用计数实现计较简单,每个对象对应一个引用计数器,当有被引用的时候就+1,引用被释放的时候-1,这样当该值为0时,则对象已死。这一算法有个问题就是:当出现相互引用(类似于多线程死锁的情况)的时候,对象虽死,但是计数器却不为0。
        可达性分析也叫根节点搜索算法,其实现是根据图的搜索(当然,图的搜索其实就是树遍历),JVM首先创建一个GC Root的根节点,所有创建的对象在存活的时候都能根据引用关系找到到达该根节点的路径,如果找不到路径,则说明该对象已死。这一算法不仅解决了引用计数的缺陷,而且不用每一对象都维护一个计数器,目前最常用的HotSpot虚拟机就采用该算法。

    二、基本垃圾回收算法

        所谓算法,就是在时间、空间、实现复杂度这三者的互博中寻求一个最优的实现。而几种垃圾回收算法也是在这几个方面各有侧重。
        标记-清除算法分为两个阶段:先对回收对象进行标记,然后统一回收。这种思路很简单,实现也很容易,但是却头两个缺点:一是标记、清除效率都很低,二是会产生碎片化,清除后空出来的空间是零散的。
        复制算法是将内存空间分为两个部分,对象同时只存在其中一个里边,当回收时将存活对象复制到另一区即可,这样就不用再进行清除了(直接覆盖即可),还不会产生生碎片。之前提到分代回收中Eden去的survivor便使用该算法。但是该算法缺点也很明显,有一半空间浪费了,典型的空间换时间。
        标记-整理算法标记-清除的升级版,上边说到,清理过程也是效率很低的,那么该算法第二步就不进行清理,而是将对象向前移动,覆盖该回收的区域,这样整理后就不会产生碎片了。年老代一般采用该算法。
        该部分可参考

    三、串行、并行、并发垃圾回收器

        首先我们要提到一点是,垃圾回收由于涉及对内存的整理,要求整理时内存状态是不能被程序改变的,也就是Stop-The-World模式下进行。当gc时间过长时,程序会出现长时间停顿,这对于响应较高的应用是不可接受的。因此,在结合线程后实现了不同方式的收集器,以满足不同需求。

    • 串行收集:串行收集使用单线程处理所有垃圾回收工作,因为无需多线程交互,实现容易,而且效率比较高。但是,其局限性也比较明显,即无法使用多处理器的优势,所以此收集适合单处理器机器。当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机器上。一般只能用于小型应用。
    • 并行收集:并行收集使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,越能体现出并行收集器的优势。 适用情况:“对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。
    • 并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收工作时,需要暂停整个运行环境,而只有垃圾回收程序在运行,因此,系统在垃圾回收时会有明显的暂停,而且暂停时间会因为堆越大而越长。适用情况:“对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。

        此外还要提到的一点是,因为不同系统、不同JVM对于线程的处理不同,所以这几个算法的的实现都是依赖于垃圾收集器的实现的,我们可以通过JVM参数来指定不同收集器进行处理。

        本次JVM相关算法介绍完毕,下次将重点放在JVM监控、调优等方面,由于个人没有太多实践经验,这部分主要会整理相关资料。    


  • 相关阅读:
    Java学习之集合
    No module named 'requests'---问题解决记录
    jmeter中设置线程数与设置集合点的区别
    【转载】jmeter将上一个接口返回值作为下一个接口的请求参数
    TortoiseSVN 使用教程
    Xenu Link Sleuth 简单好用的链接测试工具
    Nginx的启动、停止与重启---linux
    深入理解HTTP协议、HTTP协议原理分析
    正则表达式
    Python基础教程(022)--Pycharm快速体验
  • 原文地址:https://www.cnblogs.com/good-temper/p/3577426.html
Copyright © 2011-2022 走看看