• JVM垃圾收集算法


    本文是基于周志明的《深入理解Java虚拟机》

    垃圾收集算法    Java 语言的一大特点就是可以进行自动垃圾回收处理,而无需开发人员过于关注系统资源,例如内存资源的释放情况。自动垃圾收集虽然大大减轻了开发人员的工作量,但是也增加了软件系统的负担。    由于垃圾收集算法的实现涉及大量的程序细节,而且各个平台的虚拟机操作内存的方法各不相同,因此下面只讨论几种算法的思想。

    1、标记-清除算法 (Mark-Sweep)

        是最基础的收集算法,之所以这么说,是因为下面的其它算法都是基于这种思路并对其不足进行改进而得到的。
      
      标记-清除算法将垃圾回收分为两个阶段:
        ①.标记阶段:首先标记出所有需要回收的对象。
        如何标记,查看这篇博客http://blog.csdn.net/ochangwen/article/details/51406779
        ②.清除阶段:标记完成后,统一回收被标记的对象

      缺点:
        ①.效率问题:标记清除过程效率都不高。
        ②.空间问题:标记清除之后会产生大量的不连续的内存碎片(空间碎片太多可能会导致以后在程序运行过程中需要分配较大的对象时,无法找到足够的连续的内存空间而不得不提前触发另一次垃圾收集动作。)
    -------------------------------------------------------------------------------------------------------------------

    2、复制算法 (Copying)

      2.1.算法思想:
        1).将现有的内存空间分为两快,每次只使用其中一块.
        2).当其中一块时候完的时候,就将还存活的对象复制到另外一块上去。
        3).再把已使用过的内存空间一次清理掉。

      2.2.优点:
        1).由于是每次都对整个半区进行内存回收,内存分配时不必考虑内存碎片问题。
        2).只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
         
      2.3.缺点:
        1).内存减少为原来的一半,太浪费了。
        2).对象存活率较高的时候就要执行较多的复制操作,效率变低。
        3).如果不使用50%的对分策略,老年代需要考虑的空间担保策略。

      2.4.演进
        并不需要根据1:1划分内存空间,而是将内存划分为一块较大的EdenSpace和两块较小的SurvivorSpace
    JavaHeap内存回收模型(当前商业虚拟机大多使用此算法回收新生代

    ---------------------------------------------------------------------------------------------------------------------------

    3、标记-压缩算法 (Mark-Compact)

        由于复制算法的缺点,及老年代的特点(存活率高,没有额外内存对其进行空间担保),老年代一般不使用复制算法。  3.1.算法思想    1).标记阶段:首先标记出所有需要回收的对象。与“标记-清除”一样    2).让存活的对象向内存的一段移动。而不跟“标记-清除”直接对可回收对象进行清理    3).再清理掉边界以外的内存。     由于老年代存活率高,没有额外内存对老年代进行空间担保,那么老年代只能采用标记-清理算法或者标记整理算法。 -------------------------------------------------------------------------------------------------------------------------

    4、分代收集算法 (Generational Collecting)

        当前的商业虚拟机的垃圾收集都采用,把Java堆分为新生代和老年代。根据各个年代的特点采用最适当的收集算法。
        在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,选用:复制算法
        在老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清除”或者“标记-整理”算法来进行回收。

    典型的垃圾回收器

    垃圾收集算法是内存回收的理论基础,而垃圾收集器就是内存回收的具体实现。

    下面介绍一下HotSpot(JDK 7)虚拟机提供的几种垃圾收集器,用户可以根据自己的需求组合出各个年代使用的收集器。

    1.Serial&Serial Old

    Serial和Serial Old收集器是最基本最古老的收集器,是一个单线程收集器,并且在它进行垃圾收集时,必须暂停所有用户线程。Serial收集器是针对新生代的收集器,采用的是Copying算法,Serial Old收集器是针对老年代的收集器,采用的是Mark-Compact算法。它的优点是实现简单高效,但是缺点是会给用户带来停顿。

    2.ParNew

    ParNew收集器是Serial收集器的多线程版本,使用多个线程进行垃圾收集。

    3.Parallel Scavenge

    Parallel Scavenge收集器是一个新生代的多线程收集器(并行收集器),其采用的是Copying算法,该收集器与前两个收集器有所不同,它主要是为了达到一个可控的吞吐量。

    4.Parallel Old

    Parallel Old是Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和Mark-Compact算法。

    5.CMS

    CMS(Current Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它是一种并发收集器,采用的是Mark-Sweep算法。

    6.G1

    G1收集器是当今收集器技术发展最前沿的成果,它是一款面向服务端应用的收集器,它能充分利用多CPU、多核环境。因此它是一款并行与并发收集器,并且它能建立可预测的停顿时间模型。

    最后介绍一下有关收集器设置的JVM常见配置方式:

    [java] view plain copy
     
    1. -XX:+UseSerialGC: //设置串行收集器  
    2. -XX:+UseParallelGC: //设置并行收集器  
    3. -XX:+UseParalledlOldGC: //设置并行年老代收集器  
    4. -XX:+UseConcMarkSweepGC: //设置并发收集器  
    5. //并行收集器设置  
    6. -XX:ParallelGCThreads=n: //设置并行收集器收集时使用的CPU数,并行收集线程数  
    7. -XX:MaxGCPauseMillis=n: //设置并行收集最大暂停时间  
    8. -XX:GCTimeRatio=n: //设置垃圾回收时间占程序运行时间的百分比,公式为1/(1+n)  
    9. //并发收集器设置  
    10. -XX:+CMSIncrementalMode: //设置为增量模式。适用于单CPU情况  
    11. -XX:ParallelGCThreads=n: //设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数  
  • 相关阅读:
    日志管理工具logrotate
    springboot2整合logback.xml动态修改日志打印级别
    mybatis框架之装饰模式
    mybatis源码分析之06二级缓存
    后勤信息反馈---场景描述
    《人月神话》读后感---计算机产品的文档
    android studio 使用第三方模拟器连接方法
    第八周总结
    Android Studio 和 SDK 下载、安装和环境变量配置
    求最大子数组并单步显示
  • 原文地址:https://www.cnblogs.com/AndyAo/p/8227895.html
Copyright © 2020-2023  润新知