`

[转] JVM gc参数设置与分析

阅读更多

原文:

概述

java的最大好处是自动垃圾回收,这样就无需我们手动的释放对象空间了,但是也产生了相应的负效果,gc是需要时间和资源的,不好的gc会严重影响系统的系能,因此良好的gc是JVM的高性能的保证。JVM堆分为新生代,旧生代和年老代,新生代可用的gc方式有:串行gc(Serial Copying),并行回收gc(Parellel Scavenge),并行gc(ParNew),旧生代和年老代可用的gc方式有串行gc(Serial MSC),并行gc(Parallel MSC),并发gc(CMS)。

回收方式的选择

jvm有client和server两种模式,这两种模式的gc默认方式是不同的:

client模式下,新生代选择的是串行gc,旧生代选择的是串行gc

server模式下,新生代选择的是并行回收gc,旧生代选择的是并行gc

一般来说我们系统应用选择有两种方式:吞吐量优先和暂停时间优先,对于吞吐量优先的采用server默认的并行gc方式,对于暂停时间优先的选用并发gc(CMS)方式。

CMS gc

CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。在我们的应用中,因为有缓存的存在,并且对于响应时间也有比较高的要求,因此希望能尝试使用CMS来替代默认的server型JVM使用的并行收集器,以便获得更短的垃圾回收的暂停时间,提高程序的响应性。

CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:

初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。

其中的1,3两个步骤需要暂停所有的应用程序线程的。第一次暂停从root对象开始标记存活的对象,这个阶段称为初始标记;第二次暂停是在并发标记之后,暂停所有应用程序线程,重新标记并发标记阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)。第一次暂停会比较短,第二次暂停通常会比较长,并且 remark这个阶段可以并行标记。

而并发标记、并发清除、并发重设阶段的所谓并发,是指一个或者多个垃圾回收线程和应用程序线程并发地运行,垃圾回收线程不会暂停应用程序的执行,如果你有多于一个处理器,那么并发收集线程将与应用线程在不同的处理器上运行,显然,这样的开销就是会降低应用的吞吐量。Remark阶段的并行,是指暂停了所有应用程序后,启动一定数目的垃圾回收进程进行并行标记,此时的应用线程是暂停的。

full gc

full gc是对新生代,旧生代,以及持久代的统一回收,由于是对整个空间的回收,因此比较慢,系统中应当尽量减少full gc的次数。

如下几种情况下会发生full gc:

  1. 旧生代空间不足
  2. 持久代空间不足
  3. CMS GC时出现了promotion failed和concurrent mode failure
  4. 统计得到新生代minor gc时晋升到旧生代的平均大小小于旧生代剩余空间
  5. 直接调用System.gc,可以DisableExplicitGC来禁止
  6. 存在rmi调用时,默认会每分钟执行一次System.gc,可以通过-Dsun.rmi.dgc.server.gcInterval=3600000来设置大点的间隔。

Gc日志参数

通过在tomcat启动脚本中添加相关参数生成gc日志

  • -verbose.gc开关可显示GC的操作内容。打开它,可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。
  • 打开-xx:+printGCdetails开关,可以详细了解GC中的变化。
  • 打开-XX:+PrintGCTimeStamps开关,可以了解这些垃圾收集发生的时间,自JVM启动以后以秒计量。
  • 最后,通过-xx:+PrintHeapAtGC开关了解堆的更详细的信息。
  • 为了了解新域的情况,可以通过-XX:+PrintTenuringDistribution开关了解获得使用期的对象权。
  • -Xloggc:$CATALINA_BASE/logs/gc.log gc日志产生的路径
  • -XX:+PrintGCApplicationStoppedTime 输出GC造成应用暂停的时间
  • -XX:+PrintGCDateStamps GC发生的时间信息

Opentsdb打开Gc参数

 
 
 
 
 
# tsdb.local
GCARGS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps\
 -XX:+PrintTenuringDistribution -Xloggc:/tmp/tsd-gc-`date +%s`.log"
if test -t 0; then # if stdin is a tty, don't turn on GC logging.
  GCARGS=
fi
# The Sun JDK caches all name resolution results forever, which is stupid.
# This forces you to restart your application if any of the backends change
# IP. Instead tell it to cache names for only 10 minutes at most.
FIX_DNS='-Dsun.net.inetaddr.ttl=600'
JVMARGS="$JVMARGS $GCARGS $FIX_DNS"

常用JVM参数

分析gc日志后,经常需要调整jvm内存相关参数,常用参数如下

  • -Xms:初始堆大小,默认为物理内存的1/64(<1GB);默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制
  • -Xmx:最大堆大小,默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
  • -Xmn:新生代的内存空间大小,注意:此处的大小是(eden+ 2 survivor space)。与jmap -heap中显示的New gen是不同的。整个堆大小=新生代大小 + 老生代大小 + 永久代大小。在保证堆大小不变的情况下,增大新生代后,将会减小老生代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
  • -XX:SurvivorRatio:新生代中Eden区域与Survivor区域的容量比值,默认值为8。两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。
  • -Xss:每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。应根据应用的线程所需内存大小进行适当调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用, 如果栈不是很深, 应该是128k够用的,大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"-Xss is translated in a VM flag named ThreadStackSize”一般设置这个值就可以了。
  • -XX:PermSize:设置永久代(perm gen)初始值。默认值为物理内存的1/64。
  • -XX:MaxPermSize:设置持久代最大值。物理内存的1/4。

示例

下面对如下的参数进行分析:

JAVA_OPTS="-server -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4
-verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log 
-Djava.awt.headless=true 
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails 
-Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000
-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15"
  • -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m

Xms,即为jvm启动时得JVM初始堆大小,Xmx为jvm的最大堆大小,xmn为新生代的大小,permsize为永久代的初始大小,MaxPermSize为永久代的最大空间。

  • -XX:SurvivorRatio=4

SurvivorRatio为新生代空间中的Eden区和救助空间Survivor区的大小比值,默认是32,也就是说Eden区是 Survivor区的32倍大小,要注意Survivo是有两个区的,因此Surivivor其实占整个young genertation的1/34。调小这个参数将增大survivor区,让对象尽量在survitor区呆长一点,减少进入年老代的对象。去掉救助空间的想法是让大部分不能马上回收的数据尽快进入年老代,加快年老代的回收频率,减少年老代暴涨的可能性,这个是通过将-XX:SurvivorRatio 设置成比较大的值(比如65536)来做到。

  • -verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log

将虚拟机每次垃圾回收的信息写到日志文件中,文件名由file指定,文件格式是平文件,内容和-verbose:gc输出内容相同。

  • -Djava.awt.headless=true

Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。

  • -XX:+PrintGCTimeStamps -XX:+PrintGCDetails

设置gc日志的格式

  • -Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000

指定rmi调用时gc的时间间隔

  • -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15

采用并发gc方式,经过15次minor gc 后进入年老代

  • Xms 是指设定程序启动时占用内存大小。一般来讲,大点,程序会启动的快一点,但是也可能会导致机器暂时间变慢。
    
    Xmx 是指设定程序运行期间最大可占用的内存大小。如果程序运行需要占用更多的内存,超出了这个设置值,就会抛出OutOfMemory异常。
    
    Xss 是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程大约需要占用多少内存,可能会有多少线程同时运行等。
    
    以上三个参数的设置都是默认以Byte为单位的,也可以在数字后面添加[k/K]或者[m/M]来表示KB或者MB。而且,超过机器本身的内存大小也是不可以的,否则就等着机器变慢而不是程序变慢了。
    
    -Xmsn
    Specify the initial size, in bytes, of the memory allocation pool. This value must be a multiple of 1024 greater than 1MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
    Examples:
           -Xms6291456
           -Xms6144k
           -Xms6m
          
    -Xmxn
    Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
    Examples:
           -Xmx83886080
           -Xmx81920k
           -Xmx80m
    
    -Xssn
    Set thread stack size. 
    

一些常见问题

  • 为了避免Perm区满引起的full gc,建议开启CMS回收Perm区选项:
    +CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled
    
  • 默认CMS是在tenured generation沾满68%的时候开始进行CMS收集,如果你的年老代增长不是那么快,并且希望降低CMS次数的话,可以适当调高此值:
    -XX:CMSInitiatingOccupancyFraction=80
    
  • 遇到两种fail引起full gc:Prommotion failed和Concurrent mode failed时:

Prommotion failed的日志输出大概是这样:

[ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K( 166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]

这个问题的产生是由于救助空间不够,从而向年老代转移对象,年老代没有足够的空间来容纳这些对象,导致一次full gc的产生。解决这个问题的办法有两种完全相反的倾向:增大救助空间、增大年老代或者去掉救助空间。

Concurrent mode failed的日志大概是这样的:

(concurrent mode failure): 1228795K->1228598K(1228800K), 7.6748280 secs] 1911483K->1681165K(1911488K), [CMS Perm : 225407K->225394K(262144K)], 7.6751800 secs]

问题的产生原因是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。

Gc日志分析工具

GCHisto

http://java.net/projects/gchisto

直接点击gchisto.jar就可以运行,点add载入gc.log

统计了总共gc次数,youngGC次数,FullGC次数,次数的百分比,GC消耗的时间,百分比,平均消耗时间,消耗时间最小最大值等

  • 统计的图形化表示

  • YoungGC,FullGC不同消耗时间上次数的分布图,勾选可以显示youngGC或fullGC单独的分布情况

  • 整个时间过程详细的gc情况,可以对整个过程进行剖析

GCLogViewer

http://code.google.com/p/gclogviewer/

点击run.bat运行

整个过程gc情况的趋势图,还显示了gc类型,吞吐量,平均gc频率,内存变化趋势等

Tools里还能比较不同gc日志:

HPjmeter

工具很强大,但只能打开由以下参数生成的GC log, -verbose:gc -Xloggc:gc.log,添加其他参数生成的gc.log无法打开。

GCViewer

http://www.tagtraum.com/gcviewer.html

这个工具用的挺多的,但只能在JDK1.5以下的版本中运行,1.6以后没有对应。

garbagecat

http://code.google.com/a/eclipselabs.org/p/garbagecat/wiki/Documentation

其它监控方法

  • Jvisualvm

Jvisualvm动态分析jvm内存情况和gc情况,插件:visualGC

jvisualvm还可以heapdump出对应hprof文件(默认存放路径:监控的服务器 /tmp下),利用相关工具,比如HPjmeter可以对其进行分析

grep Full gc.log粗略观察FullGC发生频率

jstat –gcutil [pid] [intervel] [count]
  • jmap

jmap -histo pid可以观测对象的个数和占用空间

jmap -heap pid可以观测jvm配置参数,堆内存各区使用情况

  • jprofiler,jmap dump出来用MAT分析

如果要分析的dump文件很大的话,就需要很多内存,很容易crash。

所以在启动时,我们应该加上一些参数: Java –Xms512M –Xmx1024M –Xss8M

参考资料:

探秘Java虚拟机——内存管理与垃圾回收http://sunbean.blog.51cto.com/972509/768034

分享到:
评论

相关推荐

    JVM参数设置详细说明

    JVM参数设置详细说明、JVM 参数设置详细说明 1: heap size a: -Xmx 指定jvm的最大heap大小,如:-Xmx=2g b: -Xms 指定jvm的最小heap大小,如:-Xms=2g,高并发应用,建议和-Xmx一样,防止因为内存收缩/突然增大带来...

    JVM Full GC 之 MAT工具分析实践-阿沐1

    1.查看当前机器上所有运行的java进程名称与pid(进程编号) 2.显示指定的jvm进程所有的属性设置和配置参数 1.方法一:使用jdk的jmap命令 2.方

    深入JVM内核 - 原理、诊断与优化

    Serial ParNew等GC参数 GC的参数搭配实例分析 介绍GC的设置参数,并分析相关的案列。 第六课 类装载 class装载流程 ClassLoader模式 ClassLoader的使用实例分析 热替换例子 详细介绍ClassLoader的原理和应用。分析...

    java学习之JVM调优相关说明

    将机器的JVM参数设置到最优 一般的Java都不需要进行JVM优化 减少代码层面造成的GC问题(STW) 减少使用全局变量、大对象以及减少创建对象的数量 通过代码解决GC情况比优化JVM参数更好 架构和代码调优等级优先于JVM...

    虚拟机参数配置

    JVM参数设置、分析,介绍JVM、GC的一些重要参数的设置来提高系统的性能。

    JVM优化|java虚拟机优化

    - 掌握jvm的运行参数以及参数的设置 - 掌握jvm的内存模型(堆内存) - 掌握jamp命令的使用以及通过MAT工具进行分析 - 掌握定位分析内存溢出的方法 - 掌握jstack命令的使用 - 掌握VisualJVM工具的使用 - 了解什么是...

    resin-jvm 调优

    1.JVM的gc概述 gc即垃圾收集机制是指...在设置了上述参数后可以通过Visualgc 来观察垃圾回收的一些参数状态,再做相应的调整来改善性能。一般的标准是减少fullgc的次数,最好硬件支持使用并行垃圾回收(要求多CPU)。

    JVM调优相关内容教程吐血整理干货.md

    JVM常见参数 堆栈相关 GC相关 其他 Java常用调优命令和工具 JVM调优相关 JVM常见参数 堆栈相关 -Xss 调整线程栈大小。 -Xms 设置堆内存初始化大小。 -Xmx / -XX:MaxHeapSize=? 设置堆内存最大值。 -Xmn / -XX:...

    jvm调优的一些相关参数

    应用出现OutOfMemory等内存异常,应用中有使用本地缓存且占用大量内存空间,系统吞吐量与响应性能不高或不降,Heap内存(老年代)持续上涨达到设置的最大内存值,Full GC 次数频繁。等有解决方法 JVM调优主要是针对...

    java程序启动参数设置优化

    不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。

    starcwang-canal_mysql_elasticsearch_sync-master.zip

    很多人上手ES的时候,对GC一点概念都没有就去网上抄各种JVM“优化”参数,却仍然被heap不够用,内存溢出这样的问题搞得焦头烂额。即使对于JVM GC机制不够熟悉,头脑里还是需要有这么一个基本概念: 应用层面生成大量...

    zxporz-ESClientRHL-es7.zip

    很多人上手ES的时候,对GC一点概念都没有就去网上抄各种JVM“优化”参数,却仍然被heap不够用,内存溢出这样的问题搞得焦头烂额。即使对于JVM GC机制不够熟悉,头脑里还是需要有这么一个基本概念: 应用层面生成大量...

    成为JavaGC专家(4)

    在第二篇文章成为JavaGC专家PartII—如何监控Java垃圾回收机制中我们学到了JVM到底是如何执行垃圾回收,我们如何监控GC,以及那些工具可以使得监控过程更高效。在第三篇文章成为JavaGC专家系列PartIII–如何优化Java...

    Tomcat内存溢出的三种情况及解决办法分析

    对于前两种情况,在应用本身没有内存泄露的情况下可以用设置tomcat jvm参数来解决。(-Xms -Xmx -XX:PermSize -XX:MaxPermSize) 最后一种可能需要调整操作系统和tomcat jvm参数同时调整才能达到目的。 第一种...

    weblogic内存调优

    JVM内存的调优 1. Heap设定与垃圾回收Java Heap分为3个区,Young,Old和Permanent。Young保存刚实例化的对象。...JVM的Heap分配可以使用-X参数设定, -Xms 初始Heap大小 -Xmx java heap最大值 …… ……

    关于Flume的优化和高可用

    文章目录Flume优化一、内存参数优化(减少GC)1)-xmx和-xms设置相同值,避免在 GC 后调整堆大小带来的压力。2)JVM heap(堆内存)设置4G或更高二、channel优化Flume如何保证数据安全(高可用)事务机制Flume解决...

    Java虚拟机

    全书共分为五大部分,围绕内存管理、执行子系统、程序编译与优化、高效并发等核心主题对JVM进行了全面而深入的分析,深刻揭示了JVM的工作原理。第一部分从宏观的角度介绍了整个Java技术体系、Java和JVM的发展历程、...

    java面试常见基础(深层次,高级研发)

    2.5. 辅助信息参数设置 12 2.6. 关于参数名称等 13 3. JVM服务参数调优实战 14 3.1. 大型网站服务器案例 14 3.2. 内部集成构建服务器案例 15 4. 常量池在jvm的哪个空间里边? 17 5. jvm垃圾回收是什么时候触发的? ...

Global site tag (gtag.js) - Google Analytics