zoukankan      html  css  js  c++  java
  • JVM的GC概述

    JVMGC概述

    GC即垃圾回收,是指jvm用于释放那些不再使用的对象所占用的内存。
    在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能。

    有些垃圾收集专用于特殊的应用程序。比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率。
    垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。两种常用的方法是引用计数和对象引用遍历。
    引用计数
    引用计数存储对特定对象的所有引用数,也就是说,当应用程序创建引用以及引用超出范围时,jvm必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾收集。
    对象引用遍历
    早期的jvm使用引用计数,现在大多数jvm采用对象引用遍历。对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,gc必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。

     

    基本的回收算法:

    空间维度:标记-清除、标记-压缩、标记-复制、增量回收、分代回收

    时间维度:串行回收、并发回收、并行回收

     

    标记-清除:

    标记清除的算法最简单,主要是标记出来需要回收的对象,然后然后把这些对象在内存的信息清除,会产生大量内存碎片。

     

     

     

    标记-压缩

    有时也叫标记-清除-压缩收集器,这个算法是在标记-清除的算法之上进行剪切操作,将存活对象压缩在一起,减少内存碎片。由于压缩空间需要一定的时间,会影响垃圾收集的时间。

     

    标记-复制

     

    这个算法是把内存分配为两个空间,一个空间(A)用来负责装载正常的对象信息,另外一个内存空间(B)是垃圾回收用的。

    每次把空间A中存活的对象全部复制到空间B里面,在一次性的把空间A删除。

    这个算法在效率上比标记-清除-压缩高,但是需要两块空间,对内存要求比较大,内存的利用率比较低。适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。

     

     

     

    增量回收:

    增量回收器:把堆分为多个域,每次对从一个域进行垃圾回收。这样只会早点一小部分程序暂停。

    分代回收:

    基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法进行回收。

     

    串行回收:

    用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机器

     

     

    并行回收:

    用多线程处理所有垃圾回收工作,利用多核处理器的优势。对于空间不大的区域(如young generation),采用并行收集器停顿时间很短,回收效率高,适合高频率执行。但是如果线程数量过多,导致线程之间频繁调度,也会影响性能。一半并行收集的线程是处理器的个数。

     

     

    并发回收:

    并发收集器GC时GC线程和应用线程大部分时间是并发执行,只是在初始标记(initial mark)和二次标记(remark)时需要stop-the-world,这可以大大缩短停顿时间(pause time),所以适用于响应时间优先的应用,减少用户等待时间。由于GC是和应用线程并发执行,只有在多CPU场景下才能发挥其价值,在一个N个处理器的系统上,并发收集部分使用K/N个可用处理器进行回收,一般情况下1<=K<=N/4。在执行过程中还会产生新的垃圾floating garbage(浮动垃圾),如果等空间满了再开始GC,那这些新产生的垃圾就没地方放了(并发收集器一般需要20%的预留空间用于这些浮动垃圾),这时就会启动一次串行GC,等待时间将会很长,所以要在空间还未满时就要启动GC。mark和sweep操作会引起很多碎片,所以间隔一段时间需要整理整个空间,否则遇到大对象,没有连续空间也会启动一次串行GC。采用此收集器,收集频率不能大,否则会影响到cpu的利用率,进而影响吞吐量。

     

     

    JVMGC触发原理

    JVM的GC主要是对堆内存的回收,

    一般把新生代的GC称为minor GC ,把老年代的GC成为 full GC,所谓full gc会先出发一次minor gc,然后在进行老年代的GC。

    首先想eden区申请分配空间,如果空间够,就直接进行分配,否则进行一次Minor GC。

    minor GC 首先会对Eden区的对象进行标记,标记出来存活的对象。然后把存活的对象copy到From空间。

    如果From空间足够,则回收eden区可回收的对象。

    如果from内存空间不够,则把From空间存活的对象复制到To区,

    如果TO区的内存空间也不够的话,则把To区存活的对象复制到老年代。

    如果老年代空间也不够(或者达到触发老年年垃圾回收条件的话)则触发一次full GC。

    简单方向就是Eden->From->To->Old,如下图所示:

     

     

    默认是不会对持久带(方法区)进行垃圾回收的,设置参数可回收:-XX:+CMSClassUnloadingEnabled

     

    JVM支持的GC收集器

    JVM采用的是分代回收,不同代有不同的垃圾收集器

    如图所示:连线的是可以组合使用

     

     

    各个收集器的细节我就不在这里COPY/PASTE了,SerialOld收集器在书的图中没有,是我后加上的,其实很少使用。

     

  • 相关阅读:
    “菜鸟”程序员和“大神”程序员差距在哪里?别告诉我你连菜鸟都不算!
    Android开发:为什么你的学习效率如此低,为什么你很迷茫?
    Android架构师吐槽腾讯王者荣耀的程序员,排位匹配算法怎么搞的,每次都输
    程序员如何回答面试官“请介绍一下自己”这类问题
    Android程序员事件分发机制学习笔记
    面试时,问哪些问题能试出一个 Android 应用开发者真正的水平?
    List、Set、Map的区别
    在Eclipse中使用JUnit4进行单元测试(图文教程一)
    1
    2016、11、17
  • 原文地址:https://www.cnblogs.com/metoy/p/3703128.html
Copyright © 2011-2022 走看看