JVM GC总结

一:Java内存区的简单介绍

1.堆(Heap)

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64。

JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。

默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=参数,来指定。

默认空余堆内存小于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=参数,来指定。

注:服务器一般设置-Xms和-Xmx相等以避免每次GC后频繁的调整堆的大小。

2.分代

分代是Java垃圾收集器的一大亮点,根据对象的声明周期长短,把堆分为3个代,Young,old和Permanent,根据不同代的特点采用不同的收集算法,扬长避短也。

Young(Nursery),年轻代。研究表明大部分对象都是朝生暮死,随生随灭的。因此所有收集器都为年轻代选择了复制算法。复制算法的优点是只访问活跃对象,缺点是复制成本高。因为年轻代只有少量的对象能熬到垃圾收集器,因此只需少量的复制成本。而且复制收集器只访问活跃对象,对那些占了最大比率的死对象视而不见,充分发挥了它遍历空间成本低的优点。

2.1 年轻代(Young)

年轻代分为三个区,一个是Eden区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满的时候,从第一个Survivor区复制过来的并且此时还存活的对象将被复制到年老区(Tenured)。需要注意的是,Survivor的两个区是对称的,没有先后关系,所以同一个区可能同时存在从Eden复制过来的对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从Survivor区过来的对象。而且Survivor区总有一个是空的。

2.2 Tenured(年老代)

年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命周期较长的对象。

2.3Perm(持久代)

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,这种时候需要设置一个个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:maxPermSize=<N>进行设置。

二:GC的基本概念

GC分为Full GC和Minor GC,当每一块区满时候都会引发GC。

1.Scavenge GC

一般情况下,当新对象生成,并且在Eden申请空间失败时,就触发了Scavenge GC,堆Eden区域进行GC,清除非存活的对象,并且把尚且存活的对象移到Survivor区,然后整理Survivor的两个区。

2.Full GC

对整个堆进行整理,包括Young、Tenured和Perm。Full GC比Scavenge GC要慢,因此应该尽可能减少Full GC。有如下原因可能导致Full GC:

2.1 Tenured被写满

2.2 Perm区域被写满

2.3 System.gc()被显示调用

2.4 上一次GC之后Heap的各域分配策略动态变化。

三:GC的相关介绍

1.垃圾收集器的介绍

1.1 串行收集器

使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机器。当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机器上。可以使用-XX:+UseSerialGC打开。

1.2 并行收集器

对年轻代进行并行垃圾回收,可以减少垃圾回收时间。一般在多线程处理器机器上使用。使用-XX:+UseParallelGC打开。并行收集器在JDK5.0开始引入,在JDK6.0中进行了增强,可以对年老代进行并行收集。如果年老代不使用并发收集的话,是使用单线程进行垃圾回收,因此会制约扩展能力。使用-XX:+UseParallelOldGC打开。

使用-XX:ParallelGCThrads=<N>设置并行垃圾回收的线程数。此值可以设置与机器处理器数量相等。

使用并行收集器还可以调整其他一些参数,如:设置最大垃圾回收暂停即指定垃圾回收时的最长暂停时间,通过-XX:MaxGCpauseMills=<N>指定。<N>为毫秒,如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值。设定此值可能会减少应用的吞吐量。另外还可以设置吞吐量(吞吐量为垃圾回收时间与非垃圾回收时间的比值),通过-XX:GCTimeRatio=<N>来设定,公式为1/(N+1)。例如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即1%的时间用于垃圾回收。

1.3 并发收集器

可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用。使用-XX:+UseConcmarkSweepGC打开。

并发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,跟踪可达对象。在每个年老代垃圾回收周期中,在收集初期并发收集器会对整个应用进行简短的暂停,在收集中还会再暂停一次。第二次暂停会比第一次暂停稍长,在此过程中多个线程同时进行垃圾回收工作。

并发收集器使用处理器换来短暂的停顿时间。在一个N个处理器的系统上,并发收集部分使用K/N个可用处理器进行回收,一般情况下1<=K<=N/4。
     在只有一个处理器的主机上使用并发收集器,设置为incremental mode模式也可获得较短的停顿时间。

浮动垃圾:由于在应用运行的同时进行垃圾回收,所以有些垃圾可能在垃圾回收进行完成时产生,这样就造成了"Floating Garbage",这些垃圾需要在下次垃圾回收周期时才能回收掉。所以,并发收集器一般需要20%的预留空间用于这些浮动垃圾。

Concurrent Mode Failure:并发收集器在应用运行时进行收集,所以需要保证堆在垃圾回收的这段时间有足够的空间供程序使用,否则,垃圾回收还未完成,堆空间就先满了。这种情况下将会发生"并发模式失败",此时整个应用将会暂停,进行垃圾回收。

启动并发收集器:因为并发收集在应用运行时进行收集,所以必须保证收集完成之前有足够的内存空间供程序使用,否则会出现"Concurrent Mode Failure"。通过设置-XX:CMSInitiaingOccupancyFraction=<N>指定还有多少剩余堆时进行并发收集。

收集器小结

#串行处理器

使用情况:数据量小(100MB左右),单处理器下并且对响应时间无要求的应用。

缺点:只能用于小型应用。

#并行处理器

使用情况:对吞吐量有高要求,多CPU、对应用相应时间无要求的中、大型应用。举例:后台处理、科学计算。

缺点:应用相应时间可能较长。

#并发处理器:传说中的CMS

使用情况:对响应时间有高要求,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。

2.基本收集算法

2.1 引用计数法

引用计数法的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。然后将未被引用的对象清理即可,如下图:

引用计数法的问题:

引用和去引用伴随加法和减法,影响性能。

很难处理循环引用。

2.2 标记清除

标记清除算法是现代垃圾回收算法的思想基础。标记清除是伐将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的对象。然后,在清除阶段,清除所有未被标记的对象。如下图:

标记清除法的问题

标记完成以后需要再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大,暂停时间随空间大小线性增大而且整理后堆里的碎片很多。

2.3 标记压缩法

标记压缩算法适用于存活对象较多的场合,如老年代。它在标记清除算法的基础上做了一些优化,和标记清除算法一样,标记压缩算法也首先需要从跟节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。如下图:

2.4 复制算法

与标记清除算法相比,复制算法是一种相对高效的回收方法。不适用与存活对象较多的场合,如老年代。实现思路是:将原有的内存空间分为两块(完全相同),每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。如下图:

复制算法的问题

毫无疑问复制算法最大的问题就是浪费空间。

标记整理

综合复制算法和标记清除算法的思想,将多次回收都没有死掉以及大对象保存到一个担保区,剩余的小对象复制到一个新的区域,最后将担保区和赋值完成后的区域保留,其他清除。如下图:

GC算法总结

引用计数法没有被Java采用,标记压缩相对于标记清理有优势,因为标记清理在标记完成之后还需要再遍历一次内存空间清除未被标记的对象,如果内存空间很大的话,成本将会非常高。根据分代思想,在不同的代中,选取合适的收集算法进行优化,对于少量存活对象新生代比较适合采用复制算法,而对于大量存活对象的老年代比较适合采用标记清理或者标记压缩算法。对于收集器而言,年轻代使用并行收集器好,年老代使用并发收集器好。

时间: 2024-10-08 17:26:29

JVM GC总结的相关文章

Java性能优化之JVM GC(垃圾回收机制)

Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当stop-the-world 发生时,除GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成.GC优化很多时候就是减少stop-the-world 的发生. JVM GC回收哪个区域内的垃圾? 需要注意的是,JV

JVM GC调优一则--增大Eden Space提高性能

缘起 线上有Tomcat升级到7.0.52版,然后有应用的JVM FullGC变频繁,在高峰期socket连接数,Cpu使用率都暴增. 思路 思路是Tomcat本身的代码应该是没有问题的,有问题的可能是应用代码升级,或者环境改变了,总之Tomcat的优先级排在最后. 先把应用的heap dump下来分析下: jmap -dump:format=b,file=path pid 用IBM的Heap Analyser分析,发现dubbo rpc调用的RpcInvocation对象和taglibs的Si

【甘道夫】HBase随机宕机事件处理 &amp; JVM GC回顾

一.引言 本文记录了困扰团队两周的HBase随机宕机事件的解决方案,并回顾了JVM GC调优基础知识,供各位参考. 欢迎转载,请注明出处: http://blog.csdn.net/u010967382/article/details/42394031 二.实验环境 16台虚拟机,每台4G内存,1核CPU,400G硬盘 Ubuntu 14.04 LTS (GNU/Linux 3.13.0-29-generic x86_64) CDH5.2.0套装(包括相应版本的Hadoop,HIVE,Hbase

【转载】Java性能优化之JVM GC(垃圾回收机制)

章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当stop-the-world 发生时,除GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成.GC优化很多时候就是减少stop-

深入浅出 JVM GC(3)

# 前言 在 深入浅出 JVM GC(2) 中,我们介绍了一些 GC 算法,GC 名词,同时也留下了一个问题,就是每个 GC 收集器的具体作用.有哪些 GC 收集器呢? Serial 串行收集器(只适用于堆内存 256M 以下的 JVM ) ParNew 并行收集器(Serial 收集器的多线程版本) Parallel Scavenge (PS 收集器,该收集器以吞吐量为主要目的,是1.8的默认 GC) CMS 收集器(该收集器全称 Concurrent Mark Sweep,是一种关注最短停顿

深入浅出 JVM GC(2)

# 前言 在 深入浅出 JVM GC(1) 中,限于上篇文章的篇幅,我们留下了一个问题 : 如何回收? 这篇文章将重点讲述这个问题. 在上篇文章中,我们也列出了一些大纲,今天我们就按照那个大纲来逐个讲解.在此,我将大纲复制过来. 垃圾回收算法 标记清除算法 复制算法 标记整理算法 分代收集算法(堆如何分代) 有哪些垃圾收集器 Serial 串行收集器(只适用于堆内存256m 以下的 JVM ) ParNew 并行收集器(Serial 收集器的多线程版本) Parallel Scavenge (P

JVM GC算法 垃圾回收器

JVM的垃圾回收算法有三种: 1.标记-清除(mark-sweep):啥都不说,直接上图 2.标记-整理(mark-compact) 3.复制(copy) 分代收集算法                                                    目前的垃圾回收都采用分代收集算法.也就衍生了很多垃圾收集器 "分代收集"(Generational Collection)算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法. 在新生

JVM—GC回收机制

JVM垃圾回收机制 JVM分别对新生代和旧生代采用不同的垃圾回收机制. 新生代的GC: 新生代通常存活时间较短,因此基于Copying算法来进行回收,所谓Copying算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和FromSpace或ToSpace之间copy.新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC.当连续分配对象时,对象会逐渐从eden到

JVM GC之一找出不可达对象并回收

JAVA运行时数据区域 1.程序计数器:当前线程所执行的字节码的行号指示器.一个处理器只会执行一条线程中的指令,为了线程切换后能回复到正确的执行位置,所以每条线程都需要一个独立的计数器.各条线程之间互不影响,独立存储,属于'线程私有'内存. 2.java虚拟机栈:描述的是JAVA方法执行的内存模型:每个方法执行的时候都会创建一个栈帧用于存储局部变量表.操作数栈.动态链接.方法出口等信息.每个方法的被调用直至执行完成的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程.所以也是线程私有的. 3.本