`

调整JVM ( v1.3.1) GC

    博客分类:
  • java
阅读更多

调整JVM ( v1.3.1) GC

 

 

关键词:

 

       gcgarbage collection(垃圾收集)

       infant mortality:对象分配以后很快成为垃圾,就称该对象具有infant mortality

minor collection:较小收集

major collection:较大收集

older generation:年老代

young generation:年轻代

footprint是一批工作进程的集合,以页和缓冲行数计量,在物理内存有限或者有很多处理器的系统里,footprint 可代表伸缩性

survivor spaces:生存空间

eden新的对象分配的地方

throughput:是未消耗在垃圾收集的时间占总时间的百分比

 

简介:

 

       Java 2平台越来越多的应用于大型的服务器应用,web services。这类应用要求有可扩展性,并直接受益于多线程,多处理器,sockets以及内存。然而,“big iron”性能被誉为一种艺术形式,并需要特殊技术,这种技术超出改善小型系统性能所需要的技术。幸运的是,JVMSolaris操作环境提供了线程、I/O和内存管理的有利条件。这篇文档阐述了在获取高性能的过程中所遇到的难题:GC难调。

 

       Amdahl发现大部分的工作不能被很好地并行化:某些工作总是串行的,但是并不能从并行化获得好处。Java2平台也是这种情况。特别是,JVM 1.3.1及以上版本没有并行GC,所以相对于并行收集的应用,在多处理器系统的GC的影响会增长。

 

       下图显示一个完美的理想系统,除GC外,具有良好的伸缩性。最上面的线(红色),反映了在单处理器上,只花1%时间在GC上的应用情况:这可以理解为,在32个处理器上,将会损失至少20%的Throughput。到10%时,如果不考虑单处理器应用中GC所用大量时间,那么损失的Throughput将会超过75%。

 

 

 

       这就证明了当GC花费时间比例增大的时候,在小型系统应用上所损失的Throughput可能会成为瓶颈问题。唯一的希望就是,对这个瓶颈问题的一点小改进能获得很高的性能。对于一个大型的系统来讲,调整GC则是值得的。

 

       这篇文档描述的是Solaris(SPARC Platform Edition)操作环境中的JVM 1.3.,因为这个平台提供了当今Java2平台最具伸缩性的软硬件环境。然而,这些描述的文字同样适用于其他的平台,包括Linux,Windows,Solaris(Intel Architecture)操作环境,以达到升级硬件的最大可用程度。尽管命令行选项适用于大部分的平台,但是一些平台可能有与这里所述不同的缺省值。

 

分代收集:

 

       Java 2 平台一个很强的特性之一就是屏蔽内存分配和GC的复杂性。然而,一旦GC成为瓶颈,那么就要理解所隐藏实现的细节。垃圾收集器对应用使用对象的方式作了限定,这些限定就反映在可调整参数中。这些参数可以被调整,在不牺牲抽象能力情况下获取更高的性能

 

       在一个运行的程序中,如果一个对象不再有任何引用,那么它将成为垃圾。大部分GC算法简单就是对每个可获取对象进行遍历:任何被遗弃的对象,将成为垃圾。这种算法所花的时间和实际活动对象的数量成比例,但对于具有大量活动数据的大型应用,就不可行了。

 

       JVM v1.3 集许多不同的GC算法为一体,这些不同的算法是通过分代收集结合在一起的。当GCHeap中检查每一个活动的对象时,分代收集利用大多数应用的几个属性来避免额外的工作。

 

       这些属性中,最重要的是infant mortality(对象分配以后很快成为垃圾。下图中蓝色区域显示了对象生命周期的典型分布。左边的峰值代表在分配之后能很快收集的对象。例如,重复对象(Iterator objects)在一个单循环期间,经常是活动的。

 

       一些对象存活时间越长,就越向右进行分布。例如,典型的例子是,一些在初始化时就被分配并一直存活到程序退出的对象。在这两个极端之间的是一些在中间计算中所存活的对象,就是这里那个峰值右边的区域。尽管一些应用有不同的分布情况,但大多数应用都符合这个通用图形。通过关注大多数对象的infant mortality进行有效的收集是可能的。

 

       为此,内存是分代管理的:内存池对不同代中的对象进行管理。GC是在每代中内存池满的时候进行的:如上图中竖线所示。对象分配在Eden中,那是多数初期对象变成垃圾的地方。当Eden 填满时,将会引起minor collection,在其中的存活的对象将会移动到older generation中。当older generation需要去收集的时候,那就是major collection,通常会比较慢。因为它包含了所有活动的对象。

 

       这图显示了一个调整好的系统,在该系统中,大多数对象在第一次的垃圾收集前就销毁掉了。一个对象活动时间越长,经历GC的次数就越多,GC速度就越慢。通过让大多数对象存活不到一次收集就销毁,可使GC变得十分有效。但是这种令人满意的情况,在具有不寻常的生命周期分布的应用中或造成收集频繁的大小不合适的代中就会被破坏。

 

       默认的GC参数对大多数小型应用都是有效的。对于许多服务器应用,它们并不是最佳参数。这就引出了这篇文档的主旨:

 

       如果GC成为瓶颈,你可以定制代的大小。检查详细的GC输出,研究 GC 参数对性能的影响。

收集的类型:

 

每个分代有一个相关联的GC类型,这些类型的GC可以进行配置,产生不同的算法时间,空间,中止交易。在1.3中,JVM实现了三种不同的GC

 

1,  Copying(有时,称为清扫):这个收集者可以有效的在两个或多个分代中进行对象的移动。原分代变空,可以将遗留的销毁对象进行回收。然而,需要空间去操作,并拷贝所需的footprint。在1.3.1,复制收集用于所有的minor collections.

 

2,  Mark-compact:这个收集者允许分代在适当的时候进行分配,而不需要额外的内存。然后,这种紧凑的比复制方式,速度上要慢一些。在1.3.1中,紧凑标记的方式主要用于major collection.

 

3,  Incremental(有时称为序列)。只有在命令行中设置了 -Xincgc之后,这种收集方式才起作用。借助于详细的记录,递增式的GC一次只能收集older generation的一部分,在多次minor collections之后,才尝试进行major collections。然而,如果考虑所有的Throughput的话,这种方式比紧凑标记的速度还要慢。

 

因此,复制方式是最快的,在收集时尽量使用这种方式来收集对象。

 

默认情况下的分代排列如下图所示:

在进行初始化的时候,最大的地址空间只是事实上的设定,在实际需要的时候,才分配物理内存。全部的地址空间分成young generationolder generation

 

young generation包括Eden和两个survivor spaces。对象最初分配在Eden中。其中保证一个送survivor spaces在任何时候都是空的,当垃圾收集发生时, Eden中的活的对象复制到survivor spaces,对象就在survivor spaces之间复制,直到到达最大门限值(老化),然后复制到older generation
(其它的虚拟机,包括JVM 1.2版本 For Solaris,使用两个大小相等的空间来复制,而不是使用一个大的Eden加两个小空间)。这就是说定义young generation 参数,并不能直接可比较的。

 

older generation在合适的时候,使用Mark-compact方式进行收集。名为永久代选项比较特别,因为它保存包括JVM 自身的所有反映数据(reflective data),例如类以及方法。

 

性能指标

 

衡量GC性能有两个指标。Throughput是未消耗在垃圾收集的时间占总时间的百分比,Throughput包括花在分配上的时间(不需要调整分配的速度),停顿(Pauses)是应用因为垃圾收集而停止响应的时间。

 用户对于垃圾收集有不同的需求,例如, 对于web服务器的主要尺度是Throughput,因为垃圾收集的停顿也许是不可容忍的,或者只是被网络延时所遮盖。 然而,对于交互式图形程序,短暂的延迟也会影响用户的体验。

 

一些用户对于其他一些考虑敏感,Footprint是处理的工作区,用页面和cache line 作为尺度测量.在有限的物理内存或许多处理器的系统上,footprint 可以显示伸缩性.Promptness是对象死亡和内存可用之间的时间.另一个对于分布时系统比较重要的考量标准是远程方法调用(RMI)

一般来说,选择某个代大小时要平衡考虑各种考虑因素.例如,一个非常大的young generation也许会最大化throughput,但是以footprint,promptness为代价的。小的young generationincremental collection可以使停顿时间的减少,但是以牺牲Throughput为代价的。

 

没有一种正确的方式去衡量代的大小:最好的选择是由应用使用用户需要的内存。因此,JVM 默认的GC可能并不是最好的,可以由用户使用命令去覆盖。

 

测量方法

 

Throughputfootprint是最好的标准,最好使用对于应用来说特定的手段测量。例如,一个web serverThroughput用一个客户端的来测试,同时在Solaris操作系统上,服务器的footprint可以用pmap命令来衡量。换句话说,由于GC而停顿,很容易由于JVM自己的诊断输出来得到。

 

命令行的参数: -verbosegc 显示了每次收集时的打印的信息。例如,这里时从大型的服务器应用中输出结果:

 

  [GC 325407K->83000K(776768K), 0.2300771 secs]
  [GC 325816K->83372K(776768K), 0.2454258 secs]
  [Full GC 267628K->83769K(776768K), 1.8479984 secs]

 

上面,我们看到两个minor collections和一个major collections。箭头前后的数字显示了GC前后活动对象合并大小。(在minor collections之后,这数目包括不再需要存活的对象,但是不能被回收,因为它们是活动的,或因为在older generration中还被引用)。括号里的数目是总共可获取的空间大小,它是堆的总的大小减去一个survivor spaces

 

确定代的大小

 

很多的参数都会影响分代的大小。下面的这副图举例说明了调整JVM1.3.1最重要的一点。许多参数实际用比率来表示xy, 分别用黑色部分(用x来表示),灰色部分(用y来表示)来显示。

 

 

总堆

当代满的时候,收集就发生了,throughput与可用内存的数量成反比,总可用内存是影响垃圾收集性能最重要的因素。

默认情况下,JVM在每次收集之后,增长或减少堆,来保持可用的内存和活动对象的比例。通过参数-XXMinHeapFreeRatio=<minimum> -XXMaxHeapFreeRatio=<maximum>,这个范围被设定为一个百分率,总大小在-Xms -Xmx 之间。
       Solaris上的默认参数,显示如下:

 

-XXMinFreeHeapRatio=

40

-XXMaxHeapFreeRatio=

70

-Xms

3584k

-Xmx

64m

 

大型的服务器应用经常经历两个问题。一个是启动很慢,因为初始化的堆很小,必须通过多次的major collectiosns 后调整大小。更严重的问题是默认的maximum 堆大小是对于大多数的服务器应用是不合适的。

服务器应用的设置规则是:

除非有停顿问题,否则尽量设置JVM更多的内存。默认情况下,64M太小了。设置-xms -xmx值一样大。换句话说,如果你做不好的决定,JVM是不会做补偿的。

 

确定去提高内存,正像你提高线程数一样,尽管收集不能平放,但是GC是不平放。

尽管GC不是并行的,但分配内存可以并行,所以在增加处理器的时候确保增加内存。

 

年轻代

 

第二个最有影响的问题是堆和年轻代。young generation越大,minor collections将会经常发生。然而,对于一个有限的堆大小,older generation越小,越会增加major collections的执行的次数。最佳的选择是由分布式应用的生命周期所决定。

 

默认情况下,年轻代是由NewRatio参数所决定的。例如,设置 –XXNewRatio=3 意识是young generationolder generation的比例是13。换句话说,Eden的和survivor spaces组合大小是整个堆的1/4

参数NewSizeMaxNewSize设置年轻代的最小和最大值。设置这两个值相等,就固定了young generation,正像设置-xms ,-xmx相等,就固定了整个堆的大小一样。

 

因为young generation使用复制收集,在old generation中必须有足够大的内存大小,才能保证minor collections进行。在最坏的情况下,这个值等于Eden的大小加上非空的survivor spaces的大小。如果在old generation中没有足够的内存,major collections将会发生。对于一些小应用,这种规则是很好的,因为在old generation保留的内存具有代表性,只是虚拟上的使用,而不是实际使用。但是对于需要更大堆的应用,超过虚拟堆大小一半的Eden是没有用的:只有major collections会发生。

 

如果需要,参数SurvivorRatio被用来调整survivor spaces,但是对于性能这是不重要的。例如,设置 6设置每个survivor spacesEden的比例是16;换句话说,每个survivor spaces将是young generations1/8。(不是1/7,因为有两个survivor spaces

 

如果survivor spaces太小,拷贝收集直接溢出到olde generation,如果幸存空间太大,它们将无用地空着。 每一次垃圾收集,虚拟机选择一个起始数量次数被拷贝的对象在其被以前。这个被选择的开始保持survivor spaces半空。选项XX+PrintTenuringDistribution被用来显示这个起始,和new generation中对象的年龄。它也可以用来发现应用的对象生命分布。

 

这儿是Solaris操作系统上默认值:

NewRatio

2   (client JVM 8)

NewSize

2172k

MaxNewSize

32m

SurvivorRatio

25

 

那么,服务器应用规则如下:

 

首先决定可以提供给虚拟机的总内存,然后根据young generation的大小绘制你自己的性能曲线,找到最好的设置。

除非有停顿问题,否则尽量设置JVM更多的内存。默认情况下,64M太小了。

 达到总堆大小的一半或少些时,增加 young generation 并不提高性能。
     
增加处理器的数量时,请确保增加 young generation ,因为分配可以并行。

 

其它的事项

 

对于大多数应用,permanent generation与垃圾收集器的性能无关,然而一些应用动态产生和装载许多类.JSP页面.如有必要,MaxPermSize增加permanent generation的大小。

 

一些应用通过finalizationweak/soft/phantom引用于垃圾收集器交互.这些特性在color: black; letter-spacing: 0.45p

分享到:
评论

相关推荐

    深入理解JVM&G1; GC

    开发者可以通过调整JVM参数,如设置年轻代与老年代的比例、分配的Region数量、暂停时间目标等,来优化G1 GC的行为,从而达到更好的系统性能。 总之,《深入理解JVM & G1 GC》这本书为读者提供了理解JVM内存模型和G1...

    深入理解JVM&G1GC

    资源名称:深入理解JVM & G1 GC内容简介:G1 GC提出了不确定性Region,每个空闲Region不是为某个固定年代准备的,它是灵活的,需求驱动的,所以G1 GC代表了先进性。《深入理解JVM & G1 GC》主要为学习Java语言的...

    深入理解JVM & G1 GC

    《深入理解JVM & G1 GC》这篇文章和相关压缩包文件主要聚焦于Java虚拟机(JVM)的内存管理,特别是垃圾收集器(GC)的优化,特别是G1(Garbage-First)垃圾收集器的深度解析。下面将详细阐述JVM、GC的基本概念,...

    jvm 参数及gc详解

    Java虚拟机(JVM)是Java程序运行的基础,它的配置参数和垃圾收集(GC)机制对于优化应用程序性能至关重要。本文将深入探讨JVM参数及其与Java垃圾收集相关的知识。 一、JVM参数详解 JVM参数可以分为三类:启动参数...

    jvm和gc详解及调优

    5. **GC调优**:包括如何分析GC日志,理解GC停顿(Stop-the-World)事件,以及如何通过调整JVM参数来改善系统性能,如设置堆大小、新生代与老年代的比例、存活代的晋升策略等。 6. **性能监控与诊断工具**:如...

    java jvm GC和GC Tuning 详解

    java jvm GC和GC Tuning详解

    JVM与GC调优课程视频

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

    JVM垃圾回收机制与GC性能调优

    Java虚拟机(JVM)的垃圾回收(GC)机制是Java程序高效运行的关键部分,它自动管理内存,释放不再使用的对象以避免内存泄漏。本文主要探讨JVM堆内存的结构和GC的工作原理,以及如何进行性能调优。 JVM堆是Java应用...

    JVM、GC详解及调优_jvm_JVM、GC详解及调优_

    《JVM、GC详解及调优》是一份深入解析Java虚拟机(JVM)和垃圾收集(Garbage Collection,简称GC)的详细资料。本文将根据提供的信息,深入阐述JVM的工作原理,GC的机制以及如何进行JVM的性能调优。 首先,JVM是...

    jvm gc

    5. **JVM调优**:通过调整JVM参数,可以控制GC的行为,例如设置堆大小、新生代和老年代的比例、GC策略等。常用的JVM参数有`-Xms`, `-Xmx`, `-Xmn`, `-XX:NewRatio`, `-XX:SurvivorRatio`, `-XX:+UseConcMarkSweepGC`...

    深入理解JVM & G1 GC.rar

    G1 GC提出了不确定性Region,每个空闲Region不是为某个固定年代准备的,它是灵活的,需求驱动的,所以G1 GC代表了先进性。本书主要为学习Java语言的学生、初级程序员提供GC的使用参考建议及经验,着重介绍了G1 GC ...

    JVM调优,GC算法汇总

    其中,垃圾收集(Garbage Collection, GC)是JVM管理内存的关键机制。GC的主要目标是自动回收不再使用的对象所占用的内存空间,以防止内存泄漏,并确保程序能够持续稳定地运行。 GC的工作原理可以分为几个主要阶段...

    JVM&amp;g1gc;带书签,完整版本

    4. **预测停顿时间模型**:G1允许用户预设停顿时间,它会根据当前堆状态和预期停顿时间动态调整GC策略,以尽可能满足停顿时间目标。 **G1的工作流程** G1的垃圾收集主要分为四个阶段:初始标记、并发标记、最终...

    JVM_GC调优

    合理的GC策略和参数调整对于提高Java应用的性能至关重要。理解不同GC算法的特点和适用场景,可以帮助开发者选择最适合特定应用场景的垃圾回收策略。同时,掌握JVM内存模型和垃圾回收器的工作原理也是进行有效调优的...

    Jvm1.8_GC.mmap

    GC:Gabage Collection,指JVM堆内存区域的垃圾回收 Minor GC:年轻代垃圾回收,所有的Majar GC都会触发进程暂停,只是这个实际很短 Major GC:也叫Full GC,年老代垃圾回收 年轻代和年老代的GC策略是不...

    JVM GC原理深入学习.pdf

    本文档可以作为学习JVM GC的工具书所使用,对于想深入学习JVM GC原理的同学,这一本书就足够了。因为本文档是作者花费数月时间,查阅GC相关的国内外众多资料并加以思路清晰的条目化而形成。因为篇幅所限,可能有部分...

    JVM体系结构与GC调优

    - 通过调整JVM参数解决性能问题的实例。 通过深入学习JVM体系结构和GC调优,开发者可以更好地理解和控制Java应用的内存使用,减少垃圾收集的开销,提升系统性能。这份PPT将帮助我们系统地掌握这些关键点,使我们...

    java应用JVM的GC频率观察方法

    通过对GC日志的分析,我们可以理解哪些操作导致了频繁的Full GC,从而调整堆大小、设置合适的GC策略,或者优化代码以减少不必要的内存消耗。 总的来说,理解并监控Java应用的JVM GC频率是保障系统稳定性、性能和...

    jvmgc过程介绍

    jvmgc过程介绍(jpg)

    JVM 输出 GC 日志导致 JVM 卡住

    JVM 输出 GC 日志导致 JVM 卡住 JVM 输出 GC 日志导致 JVM 卡住是一个常见的问题,尤其是在高并发和高性能应用中。这个问题的根源在于 JVM 的垃圾回收机制(Garbage Collection,GC),它会在 JVM 运行时周期性地...

Global site tag (gtag.js) - Google Analytics