`
hai0378
  • 浏览: 528372 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JVM的GC调优

 
阅读更多

谁需要GC调优

小规模程序,垃圾收集算法能很好的工作。因为里面的对象图不大,所以收集代价不高。但是如果是大规模的程序,对象成百上千,一次遍历,就算是复制收集器中只对活动对象的遍历,都需要很长的时间。所以,大规模程序,有必要深入了解GC的工作方式,了解和调整GC的参数。

关于串行和并行GC收集算法

在JVM 1.3.1以前,只有串行收集器,没有并行收集器,对于多处理器,系统吞吐量损失很大。见下图。为此,1.3.1以后(不包含1.3.1),引入了并发GC收集算法。
JVM1.4.2上,有4种垃圾收集器,默认会选择串行收集器。
JVM5.0后,则会根据用户机器的类型自动选择收集器。

 

1% GC 中的 1%是指,在一个CPU上执行且只花1%的CPU时间做垃圾收集的应用程序。
可以看到,当这个程序在处理器为30个以上的系统上运行,系统的吞吐量会下降到80%以下,即本来在单CPU系统上只花1%时间做搜集的程序会在30个以上CPU的系统上,花上20%的时间做收集。

为什么会这样呢?因为单CPU收集算法在多CPU系统上面做收集的时候,GC算法会暂停运行在任何CPU上面的程序,而自己却只能利用一个CPU做GC,所以造成了这种情况。

代Generation

自从JVM1.2以后,Sun采用了一种分代收集的策略,即将堆分成3个不同的区域,按照对象存活的时间的不同,将对象保存在不同的堆上。在不同的代上面,应用不同的收集算法,来达到最优化收集。

这3个区域叫年轻代,年老代和持久代。
除Class和Method等元数据在持久代上面分配以外,所有的对象都在年轻代上面分配,当达到一定的条件,如经过在年轻代上面N次收集后的对象,就会保存到年老代之中。

在年轻代上面进行的收集叫Minor collections,在年轻代和年老代上面同时收集叫Major collections。

Tips:

尽量不要调用System.gc(),因为这会触发Major collections。Major collections的收集效率不高,因为它要遍历几乎所有的对象。
没有办法利用API直接触发Minor collections,但是仍然有其他的调优手段。当使用完集合对象后,把引用设置为null,这样避免gc在收集过程中,无谓地遍历那些即将就要释放的对象。

实验表明,年轻代上面的对象98%的对象都会在短时间内死亡,故Minor collections可以利用拷贝收集器,只遍历那些2%存活的对象,而不用管那些死亡的对象,来提高收集效率。

为了让Minor collections能充分利用年轻代上面对象大量死亡的这个特点,就需要调整以下几个参数:
1. 收集的频率
过于频繁的收集,会导致代中对象死亡率不够高,从而需要遍历这个代中大部分的对象,使得高死亡率这个条件利用的不充分。

2. 年轻代(堆)的大小
如果堆太小,一旦堆被占满,Minor collections就不得不频繁的启动,导致情况1的发生,从而降低收集效率。

下图反应了绝大多数对象在早起死亡的这一个事实:

从图中可以看到,随着时间的推进,大部分分配的字节都被回收了,少部分留了下来。被回收的这些字节,就是所谓的die young,留下的则是live longer。

Bytes allocated 已经分配的总字节数
Bytes Surviving 存活的字节数
Minor Collections 对年轻代进行收集
Major Collections 对所有代进行收集

下图描述了JVM中对堆的划分:

Young 年轻代
Tenured 年老代
Perm 持久代

Virutal是指保留,而未分配的内存。如Perm中,加上Virtual则是Perm区域最大的大小,而刚开始并不会完全分配这个堆,只会按照最小的大小分配。

Young部分,被分为了三个部分,一个Eden,和两个大小相同的Survivor。
所有的新建对象都会在Eden中分配,当Eden占满后,即剩余的大小不足以分配新的对象时,就会触发Minor collections。对Young收集时,会将对象拷贝到其中一个Survivor,另外一个Survivor保留不用。当下次收集时,则将上次Survivor中和Eden中的活动对象,拷贝到未用的Survivor中。如此反复。当某些对象经历足够长的次数或者时间后,就会被拷贝入年老代。

如果对Young的minor collections收集到的活动对象,survivor无法完全容纳,则会将某些对象拷贝到年老代,如果年老代也不能容纳新拷贝入的对象,则触发Major collections。如果Major collections后,如果还不足以容纳,就会将Virutal中预留的空间用来扩展已有的堆。当保留Virutal分配完毕后,仍然不足时,就会抛出OutOfMemory的错误。

Tips:

不要把年老代设置的过小,一般最好能比eden+survivor更大一些,这样可以避免触发Major collections。在这个前提下,年轻代越大越好。由于Young的eden区域是拷贝收集,容易产生碎片,所以此区域越大,越不容易导致因为碎片导致的内存不足而引发的minor collections。至于survivor,则要根据情况调整。过大的survior会造成浪费,过小的survior会导致,对象被直接拷贝到年老代。

JVM1.2中,未使用上面一大二小的结构,而是将Young分成两个相同大小的区域,来回进行拷贝。

调整GC的手段

 

如何看懂上面那张图:

行,分别对应了三个代
列,分别对应了实时性要求比较高的默认的和可调节的选项, 以及对吞吐量比较高的默认的和可调节的选项,还有就是调整这3个堆的选项。

-Xmx 调整JVM启动时,保留Total Size的大小
-Xms 调整JVM启动初始化时,Total Size的大小

每一次收集后,都会根据以下两个参数调整Total Size的大小

-XX:MinHeapFreeRatio(默认,40)     Total Size中可用空间小于这个比率,就会扩展堆的大小,保持这个值
-XX:MaxHeapFreeRatio(默认,70)     Total Size中可用空间大于这个比例,就缩小堆的大小,保持这个值

Tips:

如果你的程序是服务器,那么通过将-Xmx和-Xms设置成相近,或者相同,可以阻止这种堆大小的频繁调整,造成的不必要的收集和堆增长过程。

-XX:NewRatio=3     年老代和年轻代的内存分配比率,3表示,在Total Size中,年轻代占1份,年老代3份
-XX:NewSize           年轻代初始化时的大小
-XX:MaxNewSize     如果不指定,那么年轻代可以增长不受限制,但受NewRatio的限制
-XX:SurvivorRato=6 年轻代中,eden与survivor的比率,这里eden占6份,2个survivor占2份
-XX:MaxTenuringThreshold=0 阀值,超过这个阀值的对象将被拷贝到年老代

 

 

如何进行GC调优?

 

 

 

 

1.性能的几个重要度量参数

Troughput     吞吐量,除掉GC所用的时间后,真正执行程序所在总时间的百分比
Pauses          暂停时间,即由于正在做GC,而没有响应的那些时间
Footprint        内存需求,通常用page和cache line的数量来衡量

2.查看当前的GC收集

java命令运行时,输入 -verbose:gc 参数

[GC 4802K->4383K(5312K), 0.0078566 secs]         //执行了Minor collections
[Full GC 4383K->4383K(5312K), 0.0385521 secs]   //执行了Major collections
[GC 5248K->4814K(8216K), 0.0121798 secs]         //空间仍然不够,扩展了年轻代和年老代的空间

以第一行为例

GC                       表示执行了Minor collections
4802K->4383K    表示GC执行前和执行后,堆中活动对象的大小
(5312K)               表示总的堆的大小(不算持久代,而且只算2个Survivor中的1个,即用户可用堆的大小)
0.0078566 secs   表示GC所用的时间。主要,也是首先看这个,然后再看GC/Full GC是否过于频繁。

这个信息反应了什么?年轻代太小,因为执行了Minor collections之后,活动的对象并没有显著减少,4802K->4383K, 说明初始堆分配的不够大。这个GC显然是因为eden内部碎片导致的。

用-XX:+PrintGCDetails 参数,打印更详细的信息

[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]]

// Minor collections从年轻代64575K中收集到了959K的活动对象,花费了4微秒多一点
DefNew: 64575K->959K(64576K), 0.0457646 secs

//整个堆整理后,从196016K中,收集到了133633K的活动对象
196016K->133633K(261184K)

还可以用-XX:+PrintGCTimeStamps 查看带起始和终止时间戳的信息

还有-XX:-PrintTenuringDistribution   打印出对象在放入年老代之前在年轻代做了多少次复制,如果复制次数过少,说明年轻代过小。

2类收集器

The Throughput Collector       以提高吞吐量,降低GC时间比的收集策略
The Concurrent Low Pause Collector      以提高暂停时间,以实时性为目的的收集策略

具体请看资料[1]中的内容。

其他

关于,如何遍历年轻代中的活动对象的技术,请看资料[3]。

参考资料:

1.Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html

2.Garbage Collector Ergonomics
http://java.sun.com/j2se/1.5.0/docs/guide/vm/gc-ergonomics.html

3.JVM1.4.1中的垃圾收集
http://www.ibm.com/developerworks/cn/java/j-jtp11253/

分享到:
评论

相关推荐

    用于测试jvm gc调优-share-jvm-gc.zip

    "用于测试jvm gc调优-share-jvm-gc.zip"这个压缩包文件很可能包含了一些工具、脚本或教程,用于帮助我们了解和实践JVM的垃圾收集优化。 首先,我们需要理解JVM GC的基本原理。垃圾收集器的主要任务是识别并回收不再...

    JVM与GC调优课程视频

    JVM与GC调优课程视频 〖课程介绍〗: JVM与GC调优课程视频 〖课程目录〗: 1.笔记/ ├── 第1篇-字节码篇.png?x-oss-process=style/pnp8 ├── 第2篇-类的加载篇.png?x-oss-process=style/pnp8 ├── 第3篇-运行时...

    JVM体系结构与GC调优

    **JVM体系结构与GC调优** Java虚拟机(JVM)是Java应用程序的核心组成部分,它为Java程序提供了一个运行时环境。理解JVM的体系结构对于优化Java应用的性能至关重要,尤其是垃圾收集(Garbage Collection, GC)的...

    JVM_GC调优

    ### JVM_GC调优详解 #### 一、JVM体系结构概览 Java虚拟机(JVM)作为Java程序的运行环境,其内部结构复杂且高效。为了更好地理解JVM_GC调优,我们首先来了解一下JVM的基本组成部分。 1. **类装载器子系统(Class ...

    JVM_GC_-调优总结.pdf

    ### JVM_GC_调优总结 #### 一、GC(Garbage Collection)概述 **1.1 GC的概念** - **定义**: GC(Garbage Collection),即垃圾收集器,用于跟踪内存中的对象,并自动回收那些不再被其他对象引用的对象,释放这...

    jvm常用调优方式

    JVM 内存的系统级的调优主要的目的是减少 GC 的频率和 Full GC 的次数,过多的 GC 和 Full GC 是会占用很多的系统资源(主要是 CPU),影响系统的吞吐量。特别要关注 Full GC,因为它会对整个堆进行整理,导致 Full ...

    大厂架构师-日均百万订单量的JVM优化与高级GC调优策略实战(5.8G)

    大厂架构师-日均百万订单量的JVM优化与高级GC调优策略实战(5.8G) 〖课程介绍〗: 来自顶尖大厂的架构师级JVM优化与GC调优策略实战课程,是具备有尖端技术的优化课程。在课程内容上几乎不用过多的介绍,单是查阅目录就...

    JVM性能调优总结.docx

    JVM性能调优总结 JVM性能调优是Java开发中非常重要的一方面,直接影响到系统的性能和稳定性。本文将总结JVM性能调优的经验和技巧,并提供一些实用的配置参数和建议。 一、堆大小设置 堆大小是JVM性能调优中的一个...

    JVM 监控 调优 工具

    常见的GC调优策略包括: 1. 选择合适的GC算法:如Parallel、Concurrent Mark Sweep (CMS)、G1、ZGC或Shenandoah等。 2. 调整新生代和老年代的大小,避免Full GC频繁发生。 3. 使用CMS或G1等并发收集器,减少应用...

    个人总结之—JVM性能调优实战

    ### 个人总结之—JVM性能调优实战 #### 概述 本文档是一篇关于JVM(Java虚拟机)性能调优的经典实战总结。在实际应用开发与维护过程中,JVM性能调优是一个非常重要的话题,它直接关系到应用程序运行效率、资源利用...

    jvm和gc详解及调优

    《JVM和GC详解及调优》是一本深入解析Java虚拟机(JVM)和垃圾收集(Garbage Collection,简称GC)的专业...对于团队负责人或系统架构师而言,理解JVM和GC调优也是必不可少的技能,有助于提升整个系统的稳定性和效率。

    jvm 参数调优实践

    JVM参数调优是优化Java应用程序性能的关键环节,尤其是在服务器端的应用中,如Web服务器Resin。本实践案例中,作者分别尝试了三种不同的垃圾回收(GC)策略:串行回收、并行回收和并发回收,并针对每种策略提供了...

    第04章 大促高并发系统下JVM如何调优指导03.pdf

    【标题】: "第04章 大促高并发系统下JVM如何调优指导03.pdf" 在大型促销活动期间,高并发系统的性能优化至关重要,尤其是Java虚拟机(JVM)的调优,它直接影响应用程序的响应速度和稳定性。本章节主要探讨了在亿级...

    gc调优,和jvm调优,特别详细,这是本人花人民币买的

    GC调优主要是对JVM的垃圾回收机制进行调整,以确保内存的有效利用和避免系统出现长时间的暂停。垃圾回收是JVM自动管理内存的过程,其目标是回收不再使用的对象所占用的内存空间。主要涉及以下几个方面: 1. **垃圾...

    006-jvm性能调优

    JVM性能调优 JVM(Java Virtual Machine)是Java程序执行的核心组件,负责执行Java字节码指令。JVM性能调优是Java开发者应该掌握的重要技能,以下是JVM性能调优的知识点总结: JVM基础知识 * 虚拟机:是一种软件...

    JVM性能调优-JVM内存整理及GC回收.pdf

    总结来说,JVM性能调优中的垃圾回收(GC)和内存管理是确保Java应用高效运行的关键。了解Java对象引用类型、垃圾回收算法以及分代处理垃圾的概念是进行JVM性能调优的基础。这些知识点对于准备Java面试的开发者来说,...

    JVM性能调优-JVM内存整理及GC回收

    GC调优是JVM性能优化的关键环节,涉及GC参数的调整,如新生代与老年代的比例、存活对象的阈值、并发比等。通过合理设置这些参数,可以实现更高效的内存回收,降低应用暂停时间,提高整体性能。同时,理解GC日志,...

    JVM体系结构与GC调优.pdf

    jvm体系结构与GC调优,图文齐飞,方便理解,,非常适合入门的java工程师以及性能测试工程师阅读,欢迎大家下载

    JVM参数调优及JAVA相关工具使用

    Java虚拟机(JVM)参数调优和相关工具的使用对于优化Java应用程序的性能至关重要。JVM负责管理和分配内存,其中垃圾收集(GC)是其核心功能,它自动管理内存,确保活动对象保留在内存中,同时释放不再使用的对象以...

Global site tag (gtag.js) - Google Analytics