java虚拟机之GC(转)

垃圾回收主要内容:

  1. 那些内存需要回收?

  2. 什么时候回收?

  3. 如何回收?

垃圾回收主要针对运行时数据区那些区域?

  运行时数据区的线程私有区域有:虚拟机栈,本地方法栈,程序计数器等;

                 栈中的栈帧随着方法的进入和退出执行入栈和出栈,每个栈帧的内存分配在编译期就已经确定;

                 随着线程或方法的结束,内存也随着回收;

  运行时数据区的线程共享区域有:方法区,堆;

                 方法区和堆只有程序处于运行期才能确定创建那些对象,因此这部分内存分配和回收都是动态的;

                 垃圾回收的重点区域;

一,对象存活判断

  1,引用计数算法

    给对象添加一个引用计数器,被引用时计数器值+1,引用失效计数器值-1,当计数器值为0时对象不可能再被使用;

    主流Java虚拟机未选用该算法管理内存(未解决对象之间相互循环引用的问题)

    实现简单,判断效率高(应用:FlashPlayer,Python等)

  2,可达性分析算法

    将"GC Roots"对象作为起始节点,向下搜索,搜索走过的路径为引用链;当一个对象到GC Roots没有引用链时,则该对象是不可用的;

    可作为"GC Roots"的对象:

    【1】,方法区中静态属性引用的对象

    【2】,方法区中常量引用的对象

    【3】,虚拟机栈引用的对象 (栈帧中本地变量表)

    【4】,本地方法栈中JNI引用的对象 (Native方法)

二,垃圾回收算法

  1,标记-清除算法

     定义:先标记要回收的对象,然后统一回收;

     适用:存活对象较多的垃圾回收

     缺点:

      【1】,效率低; 标记和清除的过程效率不高;

      【2】,空间问题; 标记清除后产生大量不连续的内存碎片,给大对象分配内存时没有足够连续的内存空间,导致提前出发垃圾回收动作。

      

  2,复制算法

    定义:将可用内存划分成相等大小两块,每次只使用其中一块,当这一块用完后将还存活的对象复制到另一块,

       然后将已使用过的内存一次清理。

    适用:存活对象较少的垃圾回收

    优点:每次对整个半区进行内存回收,不用考虑内存碎片问题,只要移动堆顶指针,按顺序分配内存即可;

         实现简单,运行高效

    缺点:将内存缩小了一半

    其他:

      将新生代内存按照8:1:1分为Eden,From Survivor,To Survivor三个空间,每次使用Eden和From Survivor两个空间给对象分配内存,

      当内存不足垃圾回收时,将存活对象复制到To Survivor空间,然后清理Eden和From Survivor空间;这样相当于内存指浪费了10%;

      如果10%的To Survivor空间不够存放存活对象时需要老年代进行分配担保(将存活对象通过分配担保机制直接进入老年代)

  3,标记-整理算法

    定义:先标记要回收的对象,将存活对象移至一端,最后清理端边界以外的内存

      

  4,分代收集算法

    定义:根据对象存活周期将内存划分为新生代和老年代,然后根据每个年代的特点使用合适的回收算法;

       如:新生代存活对象少可以采用复制算法; 老年代存活对象多并且没有分配担保必须使用标记清理或标记整理回收算法

三,垃圾回收器

      

  1,Serial收集器

    定义:单线程收集器,收集时必须暂停其他所有用户线程,直到收集结束。

    适用:新生代

    配置:

       -XX:PretenureSizeThreshold

         -XX:HandlePromotionFailure

    其他:

      【1】,单CPU环境Serial收集器没有现成交互开销,因此单线程的收集效率最高

      【2】,对于Client模式下的桌面应用,分配给虚拟机的内存不会很大,对于一两百兆的新生代内存回收停顿时间完全控制在一百多毫秒以内,

          停顿不频繁发生,Serial收集器是最好的选择;

      【3】,收集过程会暂停服务(Stop the world)

        

  2,ParNew收集器

    定义:是Serial收集器的多线程版本

    适用:新生代

    配置:

       -XX:PretenureSizeThreshold

         -XX:HandlePromotionFailure

         -XX:+UseConcMarkSweepGC (设置默认新生代收集器)

         -XX:+UserParNewGC (指定ParNew作为新生代收集器)

         -XX:ParallelGCThreads(限制垃圾收集的线程数)

    其他:

      【1】,与Serial收集器的控制参数,收集算法,Stop the world,对象分配规则,回收策略完全一样

      【2】,是运行Server模式下虚拟机首选新生代收集器(唯一能和CMS收集器配合工作)

          CMS是并发收集器,第一次实现让收集线程和用户线程同时工作;

          CMS属老年代收集器,无法与Parallel Scavenge配合工作;

          CMS关注回收的停顿时间(暂停用户线程时间),停顿时间越短越适合于用户交互的程序,因为有较高的响应速度

       【3】,单CPU环境没有Serial收集器效率高

      【4】,并行的多线程收集器 

       

  3,Parallel Scavenge收集器

    定义:和ParNew收集器一样的收集器,区别于主要关注吞吐量的控制和GC自适应调节策略;

       注: 吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间) ; 如果虚拟机总共运行100分钟,收集花费1分钟,则吞吐量为99%

    适用:新生代;  较高的吞吐量,导致高效率的CPU利用率,主要适合后台运算

    配置:

       -XX:MaxGCPauseMillis (控制回收停顿的最大时间 ; 注:时间越小会牺牲吞吐量和新生代空间)

       -XX:GCTimeRatio (设置吞吐量 0< X < 100 ;  垃圾回收时间占总时间的比例, 吞吐量的倒数)

                 如果将GCTimeRatio设置为19,最大GC时间占总时间的5%(即1/(1+19))

                 该值默认为99,则最大GC时间为1%    

       -XX:+UseAdaptiveSizePolicy (打开GC自适应调节策略) 

                GC自适应调节策略:虚拟机根据当前系统性能,自动调节参数已提供最合适的时间和最大吞吐量;

                          调节的参数包括:①,新生代大小(-Xmn),Eden和Survivor空间比例(-XX:SurvivorRatio)

                                  ②,晋升老年代对象的年龄(-XX:PretenureSizeThreshold)

                                   ... ... 

                GC自适应调节策略将内存管理交给虚拟机完成,只需要设置基本内存(-Xmx),停顿时间(MaxGCPauseMillis),吞吐量                                                          (GCTimeRatio)等参数给虚拟机设立优化目标;

    其他:

      【1】并行:多条垃圾回收线程并行工作,单用户线程处于等待状态

          并发:用户线程和回收线程同时进行

      【2】,并行的多线程收集器  

      

  4,Serial Old收集器

    定义:是Serial收集器的老年代版本的单线程收集器

    适用:老年代(标记-整理算法); 主要给Client模式下的虚拟机使用;

    其他:    

      如果在Server模式下主要有两大用途:①,在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用

                         ②,作为CMS收集器的后备预案(并发收集发生Concurrent Mode Failure时使用)

                     

  5,Parallel Old收集器

    定义:是Parallel Scavenge收集器的老年代版本的多线程收集器

    使用:老年代(标记-整理算法)
    其他:    

      【1】,JDK1.6开始提供该收集器

      

  6,CMS收集器(Concurrent Mark Sweep)

    定义:CMS是一款并发收集,低停顿的收集器

    关注目标:最短回收停顿时间

    适用:互联网站,B/S系统服务端(较快的响应速度,最短的系统停顿时间)较好的用户体验

    算法:标记-清除

    回收步骤:

        【1】初始标记(标记GC Roots能直接关联到的对象)(stop the world)

        【2】并发标记(进行GC Roots Tracing的过程)

        【3】重新标记(修正并发标记期间因用户程序继续运行而导致标记产生变动的对象的标记记录)(stop the world)

        【4】并发清除

         执行时间:

         T(并发标记,并发清除) > T(重新标记) > T(初始标记)

         由于耗时最长的并发标记和并发清除和用户线程一起工作,因此总体上CMS回收过程和用户线程一起并发执行的。

    配置:

        -XX:+UseConcMarkSweepGC  使用CMS收集器

         -XX:ParallelCMSThreads  设定CMS的线程数量(一般情况约等于可用CPU数量)

    缺点:

        【1】对CPU资源非常敏感

          并发阶段会占用部分线程(CPU资源)导致应用程序变慢,总吞吐量降低。

          CMS默认回收线程数 = (CPU数量 + 3)/4;    CPU数量↑回收线程↓;     CPU数量=4时回收线程占用25%CPU资源;

          CPU数量 < 4时,如CPU数量=2,则回收线程会占用一半CPU资源,导致用户程序执行速度直接降低50%,i-CMS收集器可以解决此问题;

          增量式并发收集器(i-CMS):   并发标记和并发清理时让GC线程和用户线程交替运行,尽量减少GC线程独占资源的时间

        【2】无法处理浮动垃圾,可能出现Concurrent Mode Failure失败而产生Full GC

          并发清理时用户线程还在运行而不断产生的垃圾,由于在标记之后,CMS无法当次收集清理,只能等下次GC时清理,这部分垃圾称为“浮动垃圾”;

          由于当次无法处理浮动垃圾,这些浮动垃圾又占有一定内存,又考虑要预留给用户线程足够的内存,因此让老年代提供预留空间;

          因此CMS默认老年代使用68%时触发一次回收,百分比配置(-XX:CMSInitiatingOccupancyFraction)

          如果CMSInitiatingOccupancyFraction参数设置过高,预留空间不足就会出现Concurrent Mode Failure失败,

          此时虚拟机启动Serial Old收集器进行老年代垃圾回收停顿时间变长,性能降低。

        【3】回收后空间碎片过多

          因为CMS采用标记-清除算法因此回收后会产生大量空间碎片,无法给大对象分配连续内存空间而触发Full GC;

          +UseCMSCompactAtFullCollection参数,用于在触发Full GC之前开启内存碎片整理过程,整理阶段不能并发,因此停顿时间加长。

          -XX:CMSFullGCsBeforeCompaction参数,设置进行多少次不整理的Full GC之后,进行一次带整理的Full GC。

        

   7,G1收集器

    定义:一款面向服务端应用的垃圾收集器

    算法:标记-整理

    特点:

      【1】并行与并发

        充分利用多CPU,多核环境缩短Stop the World停顿时间,使用并发方式回收避免了GC时停顿java线程

      【2】分代收集

      【3】空间整合(使用了标记-整理回收算法,避免了大量空间内存碎片的产生)

      【4】可预测的停顿(G1在追求低停顿同时建立了可预测的停顿时间模型,可以让使用者设置M毫秒内,GC所需要的时间不超过N毫秒)

    原理:

      1,G1将新生代和老年代分为大小相等的独立区域,进行全区域垃圾回收,新生代和老年代不再是物理隔离,都是部分独立区域的集合;

      2,通过计算每个区域垃圾堆积的价值(回收可得到的空间/回收所需要的时间),然后根据价值大小有优先级地进行垃圾回收,保证了回收的效率;

      3,虚拟机发现独立区域中的Reference类型数据进行写操作时,判断其他独立区域是否有Reference数据引用的对象(即老年代对象是否引用了新生代对象),

       如果是就将引用信息通过CardTable记录到独立区域的Remembered Set中,在垃圾回收的时候将Remembered Set加入到GC根节点的枚举范围,可避免使用

       可达性算法判断对象存活而进行的全堆扫描,也避免有存活对象的遗漏。

    回收步骤:

      【1】初始标记(标记GC Roots能直接关联到的对象,并修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确的Region中创建对象)(Stop the World)

      【2】并发标记(从GC Roots开始对堆中对象可达性分析,找出存活对象)(和用户线程并发进行)

      【3】最终标记(修正并发标记期间因用户线程运行的而产生变动对象的标记记录,虚拟机将这些对象记录到Remembered Set Logs中,然后合并到Rembered Set中)(Stop the World)

      【4】筛选回收(对每个独立区域进行价值排序,根据用户期望的GC停顿时间制定回收计划)

      

四,回收器的使用

  1,参数

  UseSerialGC(使用Serial + Serial Old组合收集器)

  UseParNewGC(使用ParNew + Serial Old组合收集器)

  UseConcMarkSweepGC(使用ParNew + CMS + Serial Old组合收集器;   Serial Old是CMS出现Concurrent Mode Failure失败后备用收集器)  

  UseParallelGC(使用Parallel Scavenge + Serial Old组合收集器)

  UseParallelOldGC(使用Parallel Scavenge + Parallel Old组合回收器)

  SurvivorRatio(新生代中Eden与Survivor容量比值; 默认是8,即Eden : Survivor = 8:1)

  PretenureSizeThreshold(直接晋升到老年代对象的大小,超过此参数直接被分配在老年代)

  MaxTenuringThreshold(晋升到老年代的对象年龄,每个对象Minor GC之后年龄+1, 超过此参数直接进入老年代)

  UseAdaptiveSizePolicy(动态调整Java堆中个区域大小和进入老年代的年龄)

  HandlePromotionFailure(是否允许担保分配失败,即老年代剩余空间不足应付新生代整个Eden和Survivor区所有对象都存活的极端情况)

  ParallelGCThreads(设置并行GC回收时的线程数)

  GCTimeRatio(GC时间占总时间比率,默认99,即允许1%的GC时间。 仅使用Parallel Scavenge收集器生效)

  MaxGCPauseMillis(设置GC最大停顿时间。 仅使用Parallel Scavenge收集器生效)

  CMSInitiatingOccupancyFraction(设置CMS在老年代空间被使用多少后触发一次GC, 默认68%, 仅使用CMS收集器生效)

  UseCMSCompactAtFullCollection(设置CMS完成回收后是否要进行一次内存碎片整理, 仅使用CMS收集器生效)

  CMSFullGCsBeforeCompaction(设置CMS在进行若干次回收后再启动一次内存碎片整理)

  -XX:+PrintGCDetails(打印虚拟机日志)

  2,回收器的组合使用

        


 

新生代

年老代

说明

组合1

Serial

Serial Old

都是单线程进行GC; GC时暂停所有应用线程

组合2

Serial

CMS+Serial Old

CMS是并发GC,和应用线程并发工作,不需要暂停所有应用线程

CMS出现Concurrent Mode Failure失败后使用Serial Old收集器


组合3

ParNew

CMS

用-XX:+UseParNewGC选项来开启

ParNew是Serial的并行版本,可以指定GC线程数,默认GC线程数为CPU的数量

使用-XX:ParallelGCThreads选项指定GC的线程数

用-XX:+UseConcMarkSweepGC选项,则新生代默认使用ParNew GC策略。


组合4

ParNew

Serial Old

用-XX:+UseParNewGC选项来开启

组合5

Parallel Scavenge

Serial Old

Parallel Scavenge策略主要是关注一个可控的吞吐量:应用程序运行时间 / (应用程序运行时间 + GC时间);

会使得CPU的利用率尽可能的高,适用于后台持久运行的应用程序,而不适用于交互较多的应用程序。


组合6

Parallel Scavenge

Parallel Old

Parallel Old是Serial Old的并行版本

组合7

G1

G1

-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC    开启

-XX:MaxGCPauseMillis =50 暂停时间目标

-XX:GCPauseIntervalMillis =200 暂停间隔目标

-XX:+G1YoungGenSize=512m 年轻代大小

-XX:SurvivorRatio=6  新生代中Eden与Survivor容量比值

原文地址:https://www.cnblogs.com/qcxdoit/p/9082556.html

时间: 2024-11-08 21:12:07

java虚拟机之GC(转)的相关文章

Java虚拟机(4)-GC概述,如何回收对象

1.垃圾回收概述 随着程序的不断运行,程序所产生的对象必将越来越多,而系统的内存则是有限的,所以,将没有用的对象进行清除是程序长期稳定运行的关键. 垃圾回收主要关注三个问题 什么对象应该被回收? 当然是没有用的对象.当对象不再被引用时,我们认为该对象应该被回收.如何判断对象是否还被引用,会在后面详述. 对象应该在什么时间被回收? 程序在运行过程中,对象的引用关系是一直变化的,如何选择合适的时机开始GC,也是一个重要的问题,后面详述. 应该怎样回收? 当我们知道是无用对象后,如何将无用对象清除,保

Java虚拟机:GC算法深度解析

版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 在前面的文章里介绍了可达性分析算法,它为我们解决了判定哪些对象可以回收的问题,接下来就该我们的垃圾收集算法出场了.不同的垃圾收集算法有各自不同的优缺点,在JVM实现中,往往不是采用单一的一种算法进行回收,而是采用几种不同的算法组合使用,来达到最好的收集效果.接下来详细介绍几种垃圾收集算法的思想及发展过程.  最基础的收集算法 -- 标记/清除算法        之所以说标记/清除算法是几种GC算法中最基础的算法,是因为后续的收集算法都

java虚拟机(十一)--GC日志分析

打印日志相关参数: -XX:+PrintGCDetails -XX:PrintGCTimestamps -XX:PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.log -XX:+PrintHeapAtGC -XX:+PrintTenuringDistriution:发生GC的时候,把Young区中对象的年龄打印出来 其余的参数应该能直接看懂的,就不解释了. Parallel日志: 默认情况下,都是使用Parallel收集器 JAVA_OPTS="

java虚拟机优化--gc日志

加入 wrapper.java.additional.5=-XX:+PrintGC wrapper.java.additional.6=-XX:+PrintGCDetails #wrapper.java.additional.7=-XX:+PrintGC:PrintGCTimeStamps wrapper.java.additional.7=-Xloggc:gc.log wrapper.java.additional.8=-XX:+PrintGCApplicationStoppedTime wr

Java虚拟机-垃圾收集器

垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 对于线程独占的三个区域(程序计数器.虚拟机栈.本地方法栈)不用过多的考虑垃圾回收的问题,因为他们随着线程创建而生,随着线程结束而消失.然而Java堆和方法区则不一样,一个接口的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也不一样,我们只有在程序运行的的时候才知道会创建哪些对象,这部分的内存分配是动态的,所以这也是GC所关注的方面. 如何判断对象已死

Java虚拟机5:Java垃圾回收(GC)机制详解

http://www.cnblogs.com/xrq730/p/4836700.html 哪些内存需要回收? 哪些内存需要回收是垃圾回收机制第一个要考虑的问题,所谓“要回收的垃圾”无非就是那些不可能再被任何途径使用的对象.那么如何找到这些对象? 1.引用计数法 这个算法 的实现是,给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1:当引用失效时,计数器值-1.任何时刻计数值为0的对象就是不可能再 被使用的.这种算法使用场景很多,但是,Java中却没有使用这种算法,因为这种算法很

Java虚拟机6:内存溢出和内存泄露、并行和并发、Minor GC和Full GC、Client模式和Server模式的区别

http://www.cnblogs.com/xrq730/p/4839245.html 前言 之前的文章尤其是讲解GC的时候提到了很多的概念,比如内存溢出和内存泄露.并行与并发.Client模式和Server模式.Minor GC和Full GC,本文详细讲解下这些概念的区别. 内存溢出和内存泄露的区别 1.内存溢出 内存溢出指的是程序在申请内存的时候,没有足够大的空间可以分配了. 2.内存泄露 内存泄露指的是程序在申请内存之后,没有办法释放掉已经申请到内存,它始终占用着内存,即被分配的对象可

Java虚拟机学习5、Java垃圾回收(GC)机制详解

哪些内存需要回收? 哪些内存需要回收是垃圾回收机制第一个要考虑的问题,所谓“要回收的垃圾”无非就是那些不可能再被任何途径使用的对象.那么如何找到这些对象? 1.引用计数法 这个算法的实现是,给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1:当引用失效时,计数器值-1.任何时刻计数值为0的对象就是不可能再被使用的.这种算法使用场景很多,但是,Java中却没有使用这种算法,因为这种算法很难解决对象之间相互引用的情况.看一段代码 1 /** 2 * 虚拟机参数:-verbose:g

Java虚拟机笔记(二):GC垃圾回收

为什么要了解GC 我们都知道Java开发者在开发过程中是不需要关心对象的回收的,因为Java虚拟机的原因,它会自动回收那些失效的垃圾对象.那我们为什么还要去了解GC和内存分配呢? 答案很简单:当我们需要排查各种内存溢出.内存泄漏时,当垃圾收集器成为系统达到更高并发量的瓶颈时,我们就需要对这些"自动化"的技术实施必要的监控和调节. 回收哪些对象 我们知道在Java内存运行时数据区域中,虚拟机栈.本地方法栈和程序计数器是线程隔离的数据区,随线程而生,随线程而灭:栈中的栈帧随着方法的进入和退