zoukankan      html  css  js  c++  java
  • Java垃圾回收机制

    JVM框架

    Java虚拟机HotSpot的框架:

    JVM主要组成部分:Class Loader(类加载器)、Runtime Data Area(运行时数据区)、执行引擎(Execution Engine)。

    JVM垃圾回收简介

    Step 1: Marking

     

    GC算法在扫描存活对象时通常需要从Root节点开始,扫描所有存活对象的引用,构建出对象图。

    Root:静态字段、方法参数、局部变量、CPU寄存器

    Step 2: Normal Deletion

     

    删除没有被引用的对象,释放空间。

    Step 2a: Deletion with Compacting

    删除垃圾并压缩存活的引用对象,有利于提高内存分配的效率。

    Generational Garbage Collection(分代垃圾回收)

    HotSpot堆结构:

     

    Young Generation:从eden区分配新对象,eden区满后,发生一次minor garbage collection,把eden区和一个survivor区中存活的对象移动到另一个survivor区中,存活的对象age加1,当存活的对象age达到一个阈值时晋升到Old Generation。

    Old Generation:保存存活长久对象的地方,Old Generation满后会发生major garbage collection(full garbage collection)。

    Stop the World Event:minor garbage collection和major garbage collection都是Stop the World Event,即垃圾回收的时候会暂停程序中线程的执行。

    Permanent generation:保存JVM中用于描述类和方法的元数据信息。

    整个GC的流程总结图:

     

    GC分代的基本假设是:绝大部分对象的生命周期都非常短暂,存活时间短。

    分配小对象的开销负担小,不要吝啬去创建。

    GC最喜欢这种小而短命的对象。

    让对象的生命周期尽可能短,例如在方法体内创建,使其能尽快地在YoungGC中被回收,不会晋升(romote)到年老代(Old Generation)。

    对象分配的优化:尽量避免大对象的分配,当对象大到Eden Generation放不下时,JVM只能尝试去Old Generation分配,这种情况需要尽可能避免,因为一旦在Old Generation分配,这个对象就只能被Old Generation的GC或是FullGC回收了。

    不可变对象可以减少GC的压力:Hotspot JVM为了提高YoungGC的性能,避免每次YoungGC都扫描Old Generation中的对象引用,采用了卡表(Card Table) 的方式。简单来说,当Old Generation中的对象发生对Young Generation中的对象产生新的引用关系或释放引用时,都会在卡表中响应的标记上标记为脏(dirty),而YoungGC时,只需要扫描这些dirty的项就可以了。可变对象对其它对象的引用关系可能会频繁变化,并且有可能在运行过程中持有越来越多的引用,特别是容器。这些都会导致对应的卡表项被频繁标记为dirty。而不可变对象的引用关系非常稳定,在扫描卡表时就不会扫到它们对应的项了。

    指定容器初始化大小可以减少GC的压力:每次容器扩容分配更大的空间,可能会增加GC的次数。

    各类引用:java.lang.ref.Reference有几个子类,用于处理和GC相关的引用。JVM的引用类型简单来说有几种:

    Strong Reference,最常见的引用。

    Weak Reference,当没有指向它的强引用时会被GC回收。

    Soft Reference,只当临近OOM时才会被GC回收。

    Phantom Reference,主要用于识别对象被GC的时机,通常用于做一些清理工作。

    Garbage Collector(垃圾收集器)

    JVM中会在以下情况触发回收:对象没有被引用,作用域发生未捕捉异常,程序正常执行完毕,程序执行了System.exit(),程序发生意外终止。

    JVM中标记垃圾使用的算法是一种根搜索算法。简单的说,就是从一个叫GC Roots的对象开始,向下搜索,如果一个对象不能达到GC Roots对象的时候,说明它可以被回收了。这种算法比一种叫做引用计数法的垃圾标记算法要好,因为它避免了当两个对象啊互相引用时无法被回收的现象。

    JVM中对于被标记为垃圾的对象进行回收时又分为了一下3种算法:

    1.标记清除算法,该算法是从根集合扫描整个空间,标记存活的对象,然后在扫描整个空间对没有被标记的对象进行回收,这种算法在存活对象较多时比较高效,但会产生内存碎片。

    2.复制算法,该算法是从根集合扫描,并将存活的对象复制到新的空间,这种算法在存活对象少时比较高效。

    3.标记整理算法,标记整理算法和标记清除算法一样都会扫描并标记存活对象,在回收未标记对象的同时会整理被标记的对象,解决了内存碎片的问题。

    HotSpot 1.6版使用的垃圾收集器如下图(图中两个收集器之间有连线,说明它们可以配合使用):

    1.Serial GC

    从名字上看,串行GC意味着是一种单线程的,所以它要求收集的时候所有的线程暂停。这对于高性能的应用是不合理的,所以串行GC一般用于Client模式的JVM中。

    2.ParNew GC

    是在SerialGC的基础上,增加了多线程机制。但是如果机器是单CPU的,这种收集器是比SerialGC效率低的。

    3.Parrallel Scavenge GC

    这种收集器又叫吞吐量优先收集器,而吞吐量=程序运行时间/(JVM执行回收的时间+程序运行时间),假设程序运行了100分钟,JVM的垃圾回收占用1分钟,那么吞吐量就是99%。Parallel Scavenge GC由于可以提供比较不错的吞吐量,所以被作为了server模式JVM的默认配置。

    4.ParallelOld

    是老生代并行收集器的一种,使用了标记整理算法,是JDK1.6中引进的,在之前老生代只能使用串行回收收集器。

    5.Serial Old

    是老生代client模式下的默认收集器,单线程执行,同时也作为CMS收集器失败后的备用收集器。

    6.CMS(Concurrent Mark Sweep)

    又称响应时间优先回收器,使用标记清除算法,同时它又是一个使用多线程并发回收的垃圾收集器。他的回收线程数为(CPU核心数+3)/4,所以当CPU核心数为2时比较高效些。CMS分为4个过程:初始标记、并发标记、重新标记、并发清除和并发重置。其中初始标记和重新标记是独占系统资源的,而并发标记、并发清除和并发重置是可以和用户线程一起执行的。因此,从整体上来说,CMS 收集不是独占式的,它可以在应用程序运行过程中进行垃圾回收。

    7.Garbage First(G1)

    比较特殊的是G1回收器既可以回收Young Generation,也可以回收Tenured Generation。它是在JDK6的某个版本中才引入的,性能比较高,同时注意了吞吐量和响应时间。与CMS收集器相比,G1收集器是基于标记-压缩算法的。因此,它不会产生空间碎片,也没有必要在收集完成后,进行一次独占式的碎片整理工作。

    对于垃圾收集器的组合使用可以通过下表中的参数指定:

     

    参考:

    http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

    http://coolshell.cn/articles/11541.html

    http://www.ibm.com/developerworks/cn/java/j-lo-JVMGarbageCollection/index.html

    http://www.importnew.com/16388.html

  • 相关阅读:
    WPF Caliburn 学习笔记(五)HelloCaliburn
    MSDN 教程短片 WPF 20(绑定3ObjectDataProvider)
    MSDN 教程短片 WPF 23(3D动画)
    比赛总结一
    HDU3686 Traffic Real Time Query System
    HDU3954 Level up
    EOJ382 Match Maker
    UESTC1565 Smart Typist
    HDU3578 Greedy Tino
    ZOJ1975 The Sierpinski Fractal
  • 原文地址:https://www.cnblogs.com/renpei/p/8854579.html
Copyright © 2011-2022 走看看