Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

JVM参数与性能调优

13
Jun
2014

JVM参数与性能调优

By Alex
/ in Java
/ tags JVM, 性能调优
0 Comments

本文主要适用于HotSpot JVM的参数设置与调优。

性能监控与故障处理工具
第三方工具
工具类型 说明
堆Dump分析 推荐使用MAT,参考使用Eclipse Memory Analyzer分析JVM堆Dump
栈Dump分析 推荐使用在线工具:http://fastthread.io/
低成本剖析 推荐使用JMC,参考使用Oracle Java Mission Control监控JVM运行状态
JDK命令
 命令  说明
jps

JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程

格式:
jps [ options ] [ hostid ]

选项:
-q 只输出LVMID,省略略主类的名称
-m 输出虚拟机进程启动时传递给主类main()函数的参数
-l 输出主类的全名.如果进程执行的是Jar包,输出Jar路径
-v 输出虚拟机进程启动时JVM参数

jstat

JVM Statistics Monitoring Tool,用干收集HotSpot虚拟机各方面的运行数据(类装载、内存、垃圾收集、JIT编译等)

格式:
jstat [ option vmid [interval[s|ms] [count]] ]

选项:
-class 监视类装载、卸载数、总空间及类装载所耗费的时间
-gc 监视Java堆状况,包括Eden区、2个survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息
-gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大和最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew 监视新生代GC的状况
-gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大和最小空间
-gcold 监视老年代GC的状况
-gcoldcapacity 监视内容与-gcold基本相同,输出主要关注使用到的最大和最小空间
-gcpermcapacity 输出永久代使用到的最大和最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译的方法

举例:

Shell
1
2
#每250毫秒査询一次进程2764垃圾收集的状况,一共査询20次
jstat -gc 2764 250 20
jinfo

Configuration Info for Java,实时地査看和调整虚拟机的各项参数。

格式:
jinfo [ option ] pid

举例:

Shell
1
2
jinfo -flag CMSInitiatingOccupancyFraction 1444
#输出-XX:CMSInitiatingOccupancyFraction=85
jmap

Memory Map for Java,生成虚拟机的内存转储快照(heapdump文件)

格式:
jmap [ option ] vmid

选项:
-dump 生成Java堆转储快照。格式为:-dump:[live,]format=b,file= ,live子参数说明是否只dump出存活的对象
-finalizerinfo 显示在F-Queue中等待Finalizer线程执行finalize方法的对象。只在Linux / Solaris平台下有效
-heap 显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等,只在Linux/ Solaris平台下有效
-histo 显示堆中对象统计信息.包括类、实例数量和合计容量
-permstat 以ClassLoadcr为统计口径显示永久代内存状态,只在Linux/ Solaris平台下有效
-F 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照,只 在Linux / Solaris平台下有效

举例:

Shell
1
2
3
4
5
6
jmap -dump:format=b,file=eclipse.dump 3500
#Dumping heap to ...
#Heap dump file created
 
# 显示进程5732的GC可达对象直方图
jmap -histo:live 5732
jhat

JVM Heap Dump Browser,用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上査看分析结果

注意JVM内部的类型表示方式。

jstack

Stack Trace for Java,显示虚拟机的线程快照

格式:
jstack [ option ] vmid

选项:
-F 当正常输出的请求不被响应时,强制输出线程堆栈
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用到本地方法的话,可以显示C/C++的堆栈

jcmd

不带任何参数运行jcmd,显示所有JVM进程的PID和Main类名

运行 jcmd 0 help,显示每个JVM支持的命令

命令示例:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 打印JVM参数
jcmd 25464 VM.flags
 
# 打印所有系统属性
jcmd 25464 VM.system_properties
 
# Dump出线程栈
jcmd 25464 Thread.print
 
# Dump出堆
jcmd 25464 GC.heap_dump
 
# 强制GC
jcmd 25464 GC.run
JVM调用命令格式

Shell
1
2
3
4
5
6
7
8
# options:JVM参数
# class:main方法所在类
java [ options ] class [ arguments ]
# -jar 被调用的jar包路径
java [ options ] -jar file.jar [ arguments ]
#用于GUI
javaw [ options ] class [ arguments ]
javaw [ options ] -jar file.jar [ arguments ]
标准参数
 参数 说明 
-client 使用 Java HotSpot Client VM,64bit的JDK忽略此选项,使用-server
-server 使用Java HotSpot Server VM,64bit的JDK只能是这种模式,不需要指定

-agentlib:libname[=options]

根据名称加载本地(native)JVM代理,例如:

-agentlib:hprof
-agentlib:jdwp=help
-agentlib:hprof=help

-agentpath:pathname[=options]

根据路径全名加载本地JVM代理,例如:

-agentpath:D:\JavaEE\jprofiler\7.2.2\bin\windows-x64\jprofilerti.dll=offline

-classpath classpath
-cp classpath

指定一系列分号;分隔的目录、JAR、ZIP文件路径,用于从中寻找类文件,注意,此参数覆盖CLASSPATH环境变量。如果没指定,也没有CLASSPATH环境变量,当前目录(.)为类路径
-Dproperty=value 设置JVM系统属性

-da[:pkgname | :clsname ]

 禁用断言,默认是禁用的
-ea[:pkgname | :clsname ]

 启用断言:例如:

-ea:cc.gmem.demo... ,启用demo包及其子包的断言

-esa,-dsa 启用、禁用所有system classes的断言
-help  -? 显示帮助
-jar 执行包装在jar中的类

-javaagent:jarpath[=options]

加载基于Java语言的JVM代理
-splash:imagepath  显示启动画面
-verbose:class
-verbose:gc
-verbose:jni
显示类加载信息
显示垃圾回收信息
显示JNI接口活动信息 
-version
-showversion

显示版本信息并退出
显示版本信息并继续

非标准参数
参数  说明 
-X 显示非标准参数并退出
-Xint 以解释模式运行,字节码不会编译成native代码
-Xbatch 禁止后台编译,默认情况下,后台编译字节码,编译完成前,解释执行,禁止后,必须编译完毕后才能执行方法
-Xbootclasspath:bootclasspath 设置boot class的寻找路径(JAR、ZIP或者目录)
-Xbootclasspath/a:path 附加boot class的寻找路径
-Xbootclasspath/p:path 前缀boot class的寻找路径
-Xcheck:jni 检查JNI函数的调用,比如验证参数有效性,如果失败,则退出JVM 
-Xfuture 进行严格的字节码格式检查
-Xnoclassgc 禁止类的垃圾回收
-Xincgc 启用增量的垃圾回收,默认禁用,减少垃圾回收导致的长时间系统停顿,但是会时时工作,影响程序效率
-Xloggc:file 记录垃圾回收的每个事件
-XX:AllocationPrefetchStyle=n 设置内存分配预读取风格,默认2
-XX:+|-DisableAttachMechanism 设置类似jmap、jconsole之类的命令是否可以附到(attach)到运行中的JVM,默认这个特性是禁用的
-XX:+UnlockCommercialFeatures 解锁商业特性
-XX:+|-FlightRecorder 商业特性。启用黑匣子功能

-XX:FlightRecorderOptions
=p=v,p1=v1...

配置黑匣子的选项,包括:

defaultrecording=true|false 黑匣子是持续运行,还是运行限定的时间,默认false
disk=true|false 黑匣子是否持续的写入磁盘,如果为true,defaultrecording也应该为true
dumponexit=true|false 如果JVM退出,是否生成黑匣子的dump文件
dumponexitpath=path 黑匣子dump文件的路径,同名文件被覆盖,如果指定目录,则依据时间作为文件名(7u41版本在Windows下不支持指定目录,可能是BUG)
globalbuffersize=size 数据存留占有主内存的最大空间,默认10M
loglevel=quiet|terror|warning|info|debug|trace 日志记录级别,默认info
maxage=time 磁盘数据存活最大时间,默认15分钟,只有disk=true才有意义
maxchunksize=size 数据块的最大尺寸,默认12M
maxsize=size 磁盘数据的最大尺寸,默认无限制
repository=path 临时磁盘目录的位置
samplethreads=true|false 是否启用线程样本,默认启用
settings=path 默认JAVA_HOME/jre/lib/jfr/default.jfs,包含事件的设置
stackdepth=depth 堆栈跟踪的最大深度
threadbuffersize=size 默认5kb,线程的本地缓冲大小

-XX:StartFlightRecording
=p=v,p1=v1...

启动黑匣子

compress=true|false 是否压缩黑匣子日志文件
defaultrecording=true|false
delay=time JVM启动后,延迟黑匣子记录的毫秒数
duration=time 黑匣子记录的持续时间,默认无限
filename=path 日志文件路径
name=identifier 本次记录的标识符
maxage=time
maxsize=size
settings=path

常用-XX选项
行为选项

参数与默认值

说明

-XX:-AllowUserSignalHandlers

允许用户定义的信号处理器(Solaris/Linux)

-XX:AltStackSize=16384

备选信号栈大小(Solaris,5.0-)

-XX:+FailOverToOldVerifier

如果验证失败,使用旧版本的验证启(6.0+)

-XX:PreBlockSpin=10

 -XX:+UseSpinning使用的自旋计数器,进入系统线程同步代码前,自旋的次数 (1.4.2+)

-XX:-RelaxAccessControlCheck

放松验证器的访问控制检查 ( 6.0+)

-XX:-UseSpinning

进入系统同步化代码前,在Java监视器上启用native自旋( 1.4.2 and 5.0 )

-XX:+UseThreadPriorities

使用系统native的线程优先级
性能调优选项

参数与默认值

说明

-XssN

设置线程栈大小。JDK5.0+为1M,以前为256K。减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数限制在3000~5000左右
-XmsN 设置初始内存大小(字节),必须是1024的倍数、大于1MB,可以后缀k/K、m/M、g/G
-XmxN  设置最大内存大小(字节),必须是1024的倍数、大于2MB,可以后缀k/K、m/M、g/G
-XX:PermSize 设置永久代初始占用内存大小
-XX:MaxPermSize=64m

设置永久代最大占用内存大小

-XmnN 年轻代的内存大小(Eden区+2个Survivor区)
-XX:NewRatio=2 年老代/年轻代占用空间比率
-XX:SurvivorRatio=8 年轻代Eden/Survivor区域尺寸比例,默认8:1。通常有2个Survivor区,因此8:1意味着Survivor总大小为2
-XX:PretenureSizeThreshold 用于ParNew、Serial。大于此值(字节)的对象将在年老代直接分配,避免在Eden区及Survivor区之间发生大量的内存拷贝
-XX:MaxTenuringThreshold

设置对象进入年老代前,在Survivor区复制(活过Minor GC)的最大次数,默认情况下,JVM会动态调整TenuringThreshold值。
如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代,对于年老代比较多的应用,可以提高效率
将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间

此值设置过大,则ParNew分析Survivor区对象关系时可能消耗时间过大,影响性能。

如果Survivor满了,对象会强制复制到年老代

-XX:TargetSurvivorRatio=50

JVM会试图调整TenuringThreshold期望下次Minor GC后Survivor的From区的使用量能接近50

如果设置为100,相当于禁止调整TenuringThreshold

-XX:+UseTLAB

启用线程本地分配缓冲(Thread local allocation buffers)。启用TLAB后,只有TLAB被用满了,才会尝试到Eden区域申请内存

-XX:TLABSize=n

TLAB的大小

-XX:+ResizeTLAB

是否可以动态修改TLAB大小

-XX:MaxGCPauseMillis=n

设置GC暂停时间目标。如果无法达到要求,JVM会自动调整年轻代大小

-XX:GCTimeRatio=n

控制吞吐量,设置垃圾回收时间占程序运行时间的百分比,公式为1/(1+n)

-XX:+UseSerialGC

使用串行垃圾回收 (5.0+)

-XX:+UseG1GC

启用G1垃圾回收器

-XX:+UseParallelGC

吞吐量收集器。Parallel scavenge collector,对年轻代使用并行垃圾回收(1.4.1+),不能与CMS收集器同时使用。算法针对多CPU大内存(例如10G+)进行了优化,致力于在尽量减少停顿的同时最大化吞吐量

-XX:+UseParallelOldGC

吞吐量收集器。在使用-XX:+UseParallelGC时,对年老代使用并行垃圾回收(5.0u6)

-XX:+UseParNewGC

Parallel copying collector,对年轻代使用并行垃圾回收,可与CMS收集器(-XX:+UseConcMarkSweepGC)同时使用。JDK5.0以上,JVM会根据系统配置自行设置。工作方式类似于原始的复制算法,但是使用多个线程进行并行的拷贝

-XX:ParallelGCThreads=n

并行垃圾收集使用的线程数,默认与处理器核心数相等,如果CPU很多,可以减小此值

 -XX:+UseAdaptiveSizePolicy

设置此选项后,并行收集器(Parallel Scavenge)会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低响应时间或者收集频率等,建议使用并行收集器时启用。使用-XX:+PrintAdaptiveSizePolicy跟踪动态变化

-XX:+UseConcMarkSweepGC

低停顿收集器。对年老代使用CMS垃圾回收器,同时保证应用的运行只有很短暂的停顿(1.4.1+)

-XX:+CMSConcurrentMTEnabled

CMS并发阶段(concurrent CMS phases)是否使用多线程(使用ParNewGC的情况下)。默认已经启用,设置-XX:-CMSConcurrentMTEnabled可以禁用

-XX:+CMSParallelRemarkEnabled

在CMS重标记阶段,使用多线程来降低停顿时间。默认false。不一定能达到效果,需要进行基准测试(benchmark)来确定是否开启

-XX:CMSScheduleRemarkEdenSizeThreshold

在预清理后,启动可中断预清理阶段的Eden占用最小值,默认2MB

-XX:CMSScheduleRemarkEdenPenetration

当新生代存活对象占Eden的比例超过多少时,终止preclean阶段并进入remark阶段,默认50

-XX:CMSMaxAbortablePrecleanTime

设置CMS可中断预清理(preclean)阶段最大时间,单位毫秒,超过了强制进入重标记阶段

 -XX:+CMSScavengeBeforeRemark

在CMS的重标记阶段开始前,进行YGC清理,减少重标记阶段的耗时

-XX:ConcGCThreads=n CMS垃圾收集(所有阶段)使用的线程数,提高此值可能改善垃圾回收性能,但是带来额外的同步成本(synchronization overhead)。默认的,此值不会明确设置,JVM根据-XX:ParallelGCThread来自动设置,公式为:ConcGCThreads = (ParallelGCThreads + 3)/4
-XX:+UseCMSInitiatingOccupancyOnly 禁止HostSpot自行触发CMS GC,只有在堆百分比达到阈值时才触发,配合下一条使用
-XX:CMSInitiatingOccupancyFraction 设置还剩余多少堆(百分比)时进行CMS收集,默认68%。如果年老代增长缓慢,可以增加此值。

-XX:CMSInitiatingPermOccupancyFraction

设置还剩余多少永久带(百分比)时进行CMS收集

-XX:CMSFullGCsBeforeCompaction=5

由于CMS不对内存空间进行整理,此值设置运行多少次Full GC以后对内存空间进行整理。设置此参数可能导致promotion failure

-XX:+UseCMSCompactAtFullCollection

Full GC后对年老代进行整理。可能会影响性能,但是可以消除碎片。默认true

-XX:+CMSIncrementalMode

CMS增量模式,适用于单CPU情况

-XX:+CMSClassUnloadingEnabled

启用CMS类卸载功能

-XX:+ScavengeBeforeFullGC

Full GC前清理年轻代( 1.4.1+)

-XX:+|-UseLargePages

启用大内存分页支持

-XXLargePageSizeInBytes=n

设置大内存分页的最大尺寸

-XX:MaxHeapFreeRatio=70

GC后,堆的最大空余百分比

-XX:MinHeapFreeRatio=40

GC后,堆的最小空余百分比

-XX:ReservedCodeCacheSize=32m

最大代码缓存大小

-XX:CompileThreshold=10000

进行编译前,方法被执行的次数[-client: 1,500]

-XX:ThreadStackSize=512

线程堆栈大小

-XX:+UseFastAccessorMethods

使用优化版的Get方法

-XX:+UseLargePages

使用大页(large page)内存

-XX:+UseMPSS

使用多内存页大小支持

-XX:+UseStringCache

缓存普通分配的字符串 

-XX:+UseCompressedStrings

压缩字符串 (6u21+) 

-XX:+OptimizeStringConcat

优化字符串连接(6u21+) 

-XX:MaxDirectMemorySize

NIO中通过Direct内存来提高性能,这个区域的大小默认是64M,在适当的场景可以设置大一些

-Xrs

减少JVM对系统信号(Signals)使用

-XX:+AggressiveOpts

启用在未来版本可能作为默认开启的优化选项(5.0u6)

-XX:SoftRefLRUPolicyMSPerMB=0

启用积极的软引用处理,如果软引用对垃圾回收有影响了,可以使用。默认值为每兆1000毫秒。即对于堆中每MB大小的可用空间而言,一个软引用有1秒的存活时间(在最后一个强引用的对象被回收后)

-XX:+DisableExplicitGC

禁止System.gc()的调用

-XX:+UseGCOverheadLimit

抛出OutOfMemory前,允许的GC占用虚拟机时间的最大比例(6.0+)

G1垃圾回收器相关选项
 参数 说明 
-XX:+UseG1GC 开启G1垃圾回收器
-XX:InitiatingHeapOccupancyPercent=n 堆占用了多少时触发GC,默认为45
-XX:MaxTenuringThreshold 默认15
-XX:MaxGCPauseMillis=n  
-XX:NewRatio=n 默认2
-XX:SurvivorRatio=n 默认8
-XX:ParallelGCThreads=n 并行GC的线程数
-XX:ConcGCThreads=n 并发GC使用的线程数
-XX:G1ReservePercent=n 设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险。默认值是 10%
-XX:G1HeapRegionSize=n 设置G1区域的大小。值是2的幂,范围是1 MB 到32 MB
调试选项

参数与默认值

说明

-XX:-CITime

打印JIT编译器消耗的时间(1.4.0+)

-XX:ErrorFile=./hs_err_pid%p.log

如果JVM错误发生,将错误保存到指定位置(6.0+)

例如 -XX:ErrorFile=F:\Temp\hs_err_pid%p.log(注意,在Windows的BAT脚本中%要换为%%)

-XX:+HeapDumpOnOutOfMemoryError

java.lang.OutOfMemoryError发生时,是否Dump堆镜像(1.4.2u12+, 5u7+)

-XX:+HeapDumpBeforeFullGC

在FGC前Dump出堆内存

-XX:+HeapDumpAfterFullGC 在FGC后Dump出堆内存

-XX:HeapDumpPath=/dir/

堆Dump文件的存储位置(1.4.2u12+, 5u7+)

例如 -XX:HeapDumpPath=F:\Temp\

-XX:OnError="CMD"

出现致命错误时,运行用户定义的命令(1.4.2u9+)

-XX:OnOutOfMemoryError="CMD"

出现内存溢出时,运行用户定义的命令(1.4.2u12+,6.0)

-XX:-PrintCommandLineFlags

打印附加的命令行标记 (5.0+)

-XX:-PrintCompilation

当方法被编译时,打印信息

-XX:+PrintTLAB

打印TLAB分配的情况

-XX:-PrintGC

当GC活动时,打印信息

-XX:-PrintGCDetails

打印GC详细信息 (1.4.0+)

-XX:+PrintGCDateStamps

打印GC时间,形式:2014-11-17T16:05:24.673+0800

-XX:-PrintGCTimeStamps

打印GC时间戳(相对时间),形式:0.104

-XX:-TraceClassLoading

跟踪类加载

-XX:-TraceClassResolution

跟踪常量池解析 (1.4.2+)

-XX:-TraceClassUnloading

跟踪类的卸载

-XX:+PerfDataSaveToFile

退出时保存二进制的JVM统计信息到文件

-XX:+UseCompressedOops

使用压缩指针

-XX:InlineSmallCode=n

内联之前编译好的方法,如果其大小小于n

-XX:MaxInlineSize=35

内联方法最大字节码大小

-XX:FreqInlineSize=n

频繁使用的方法内联的最大字节码大小

-Xloggc

记录GC冗长信息到文件(不指定则记录到stdout)

INI
1
2
3
4
5
6
7
8
9
10
-XX:+PrintFlagsFinal
-XX:PrintFLSStatistics=1
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:-TraceClassUnloading
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintTenuringDistribution
-Xloggc:%LOG_DIR%\gc.log

-XX:-UseGCLogFileRotation

记录GC冗长信息到文件时,启用文件轮换

-XX:NumberOfGClogFiles=1

上述文件轮换时,文件的个数

-XX:GCLogFileSize=8K

GC冗长日志的大小

-XX:+PrintGCApplicationConcurrentTime

打印GC程序并发时间

-XX:+PrintGCApplicationStoppedTime

打印GC停顿时间

-XX:+PrintTenuringDistribution

显示在Survivor区域里面有效的对象的年龄,ParNewGC分析此区域老对象的关系较为耗时

-XX:PrintFLSStatistics=N

打印FreeListSpace的统计信息,可以得到内存碎片的信息

-Xprof

剖析系统性能并输出到stdout 

JVM性能调优
JVM内存与GC设置
年轻代内存大小的选择
  1. 响应时间优先:尽量大,直到接近最低响应时间的需求限制
  2. 吞吐量优先:尽量大,最好到达Gbits
年老代内存大小的选择
  1. 响应时间优先:年老代默认CMS收集,需要考虑会话并发数、持续时间等因素,太小,造成碎片、高频回收、暂停并导致标记清除;太大,导致收集时间长。根据:CMS收集信息、次数、年轻代/年老代回收时间比率确定
  2. 吞吐量优先:一般都是较大的年轻代、较小的年老代。由于并发大,年轻代对象多,所以要求尽快收集年轻代对象,年老代存放长期存活对象
  3. 小堆引起的内存碎片问题:CMS算法不会对堆进行整理,导致碎片问题,配置 -XX:+UseCMSCompactAtFullCollection、-XX:CMSFullGCsBeforeCompaction来启用整理
使用G1垃圾回收器

7u9以后的版本,可以使用G1回收器,这是一个新型、综合的垃圾回收器。

可以使用类似如下方式启用:java -Xmx2G -Xms2G  -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1ReservePercent=20  -XX:ConcGCThreads=8

关于64bit虚拟机

一般认为64bit虚拟机的性能低于32位,所有某些时候32bit虚拟机集群比一个大的64bit虚拟机更合适。

如果JVM内存配置很大,DUMP内存映像将是非常耗时的,这和磁盘写入速度有关系

对于年轻代来说,非常大的内存空间不会对性能造成显著影响;而对于年老代,除非使用CMS垃圾回收器(默认是吞吐量优先的Parallel Old),否则可能导致很长的GC停顿(30G以内的内存可能数十秒 ,更高的内存可能数分钟),这对于用户交互式程序是无法忍受的。

CMS对于大概小于4G的堆来说,其初始标记、重标记STW时间较短,对于频繁制造垃圾的大堆,则亦可能出现问题,当CMS的工作跟不上年老代被占满的步伐时,会导致STW的串行垃圾回收器被启用,在16G内存下,这可能导致30秒或者更多的停顿,尽早(年老代被占用百分比)启用CMS,可能在一定程度上减少STW出现几率。注意,越是多核心的处理器,越可能导致CMS停顿的问题,因为CMS只会使用一个核心。

G1垃圾回收器不能解决CMS的问题,它的吞吐量甚至低于CMS。

一些最佳实践
  1. 对于G1垃圾回收器:避免使用 -Xmn 选项或 -XX:NewRatio 等其他相关选项显式设置年轻代大小,因为固定年轻代的大小会覆盖暂停时间目标
  2. 让堆的最小、最大尺寸一致
  3. 为新生代提供足够的空间,使大部分对象停留在新生代,同时,要避免老年代触发垃圾收集(保持有10-20%的空闲空间)
  4. 让新生代对象生命周期尽量短,避免使其进入年老代
  5. 避免短命的大对象,-XX:PretenureSizeThreshold设置直接进入年老代的阈值
  6. 将需要大量内存的模块使用C++等手工管理内存的语言实现
  7. 如果有海量内存,可以使用具有低延迟、无停顿GC的虚拟机,例如Azul,它的C4回收器具有这样的特征
GC日志分析
ParNew+CMS日志分析

CMS相关垃圾回收的可能原因有:

  1. System.gc() 的调用
  2. 老年代占比超过-XX:CMSInitiatingOccupancyFraction
  3. 如果启用-XX:+CMSClassUnloadingEnabled,当永久代占比超过-XX:CMSInitiatingPermOccupancyFraction
  4. 晋升失败(Promotion Failed):YGC时,Survivor区放不下所有对象,而且老年代也放不下,原因不一定是老年代空间不足,也可能是老年代碎片引起
  5. 并发模式失败(Concurrent Mode Failure ):CMS的同时进行YGC,导致CMS完成前老年代空间不足(Full Promotion Guarantee Failure),此情况下会发生Full GC。可能需要调小新生代或者减小-XX:CMSInitiatingOccupancyFraction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
'前缀时间戳,例如221810.102,表示JVM已经启动的秒数'
'时间times:user表示对于当前进程CPU消耗在user-mode的时间;sys表示对于当前进程CPU消耗在kernel-mode的时间;real表示物理时间的时间;'
'ParNew的年轻代垃圾收集(YGC),20024K为GC开始时的内存占用,497K为GC结束后的内存占用,39296K为总大小,0.0046067 为新生代局部收集消耗时间'
'后面的20024K->9715K(126720K)表示整个堆收集前后内存占用和总内存,最后的Times显示GC过程中的总时间消耗'
0.102: [GC0.102: [ParNew: 20024K->497K(39296K), 0.0046067 secs] 20024K->9715K(126720K), 0.0046827 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
0.172: [GC0.172: [ParNew: 19990K->599K(39296K), 0.0009549 secs]
 
'初始标记:STW,单线程(可以从user和real几乎相等看出),只标记ROOT能直接可达的对象,一般应该很快'
'786428K表示年老代已占用空间;后面的786432K表示年老代总空间'
221810.417: [GC [1 CMS-initial-mark: 786428K(786432K)] 4527562K(5740992K), 3.1298768 secs] [Times: user=3.14 sys=0.00, real=3.16 secs]
221813.547: [CMS-concurrent-mark-start]
'并发标记阶段,不会STW'
221814.218: [CMS-concurrent-mark: 0.670/0.671 secs] [Times: user=2.46 sys=0.00, real=0.64 secs]
'预清理,不会STW。该阶段检查并发标记阶段时从新生代晋升的对象、新分配的对象、被应用程序线程更新过的对象,减少重新标记阶段的暂停时间'
221814.218: [CMS-concurrent-preclean-start]
221814.223: [CMS-concurrent-preclean: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
'如果Eden占用量大于CMSScheduleRemarkEdenSizeThreshold(默认2M),会启动可中断预清理(不会STW)'
221814.223: [CMS-concurrent-abortable-preclean-start]
221814.223: [CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
'预清理阶段只是一个取样过程,它将新生代按一定间隔进行分块,标记起始位置,以便remark时可以并行的的对块进行Trace'
'预清理阶段最好发生一次YGC,-XX:CMSScavengeBeforeRemark可以强制重标记前发生YGC'
    221814.224: [GC[YG occupancy: 3774483 K (4954560 K)]
    221814.224: [Rescan (parallel) , 4.1513281 secs]
    221818.375: [weak refs processing, 0.0000280 secs]
    221818.375: [scrub string table, 0.0014394 secs]
        '重新标记,STW,多线程,默认通过-XX:ParallelGCThreads计算得到线程数,此阶段通常是CMS中暂停时间最长的'
        [1 CMS-remark: 786428K(786432K)] 4560911K(5740992K), 4.1529812 secs] [Times: user=28.08 sys=0.00, real=4.17 secs]
 
'并发清理,不会STW'
221818.377: [CMS-concurrent-sweep-start]
CMS: Large Block: 0x00000007f8000000; Proximity: 0x00000007f7851ea0 -> 0x00000007f7851ea0
CMS: Large block 0x0000000000000000
221818.736: [CMS-concurrent-sweep: 0.358/0.358 secs] [Times: user=0.87 sys=0.00, real=0.36 secs]
'重置,CMS数据结构重新初始化,为下一次CMS做准备'
221818.736: [CMS-concurrent-reset-start]
221818.738: [CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
 
'紧跟着一次并发模式失败的Full GC'
221890.743: [GC221890.743: [ParNew: 18434K->18434K(39296K), 0.0000233 secs]90.743: [CMS90.743: [CMS-concurrent-abortable-preclean: 0.000/0.028 secs] [Times: user=0.02 sys=0.00, real=0.03 secs]
(concurrent mode failure): 83535K->37453K(87424K), 0.0111540 secs] 101969K->37453K(126720K), [CMS Perm : 3284K->3284K(65536K)], 0.0112398 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
221890.754: [Full GC221890.754: [CMS: 37453K->37453K(87424K), 0.0051618 secs] 37453K->37453K(126720K), [CMS Perm : 3284K->3284K(65536K)], 0.0051982 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Survivor区对象年龄分布分析

开启:-XX:+PrintTenuringDistribution可以打印分布信息

1
2
3
4
5
'期望的Survivor区占用由-XX:TargetSurvivorRatio=50指定'
'threshold 即晋升的年龄限制,可由-XX:MaxTenuringThreshold指定'
Desired survivor size 2228224 bytes, new threshold 6 (max 6)
- age   1:        232 bytes,        232 total
- age   2:     478840 bytes,     479072 total '各年龄对象的字节数、数量'
 停顿时间分析

开启-XX:+PrintGCApplicationConcurrentTime、-XX:+PrintGCApplicationStoppedTime可以打印并发时间、停顿时间

1
2
3
4
'应用和GC并发执行的时间'
Application time: 0.0362382 seconds
'应用被GC停止的时间'
Total time for which application threads were stopped: 0.0039536 seconds
在启动时打印所有GC标记

开启 -XX:+PrintFlagsFinal可以打印所有GC标记

1
2
3
4
5
[Global flags]
    uintx AdaptivePermSizeWeight                    = 20              {product}          
    uintx AdaptiveSizeDecrementScaleFactor          = 4               {product}          
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10              {product}          
    ……
分析内存碎片信息

开启-XX:PrintFLSStatistics=1可以统计内存碎片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Before GC:
Statistics for BinaryTreeDictionary:
------------------------------------
Total Free Space: 11190272
Max   Chunk Size: 11190272
Number of Blocks: 1
Av.  Block  Size: 11190272
Tree      Height: 1
 
After GC:
Statistics for BinaryTreeDictionary:
------------------------------------
Total Free Space: 9993976
Max   Chunk Size: 9993976
Number of Blocks: 1
Av.  Block  Size: 9993976
Tree      Height: 1
← 基于Eclipse和Maven的Groovy开发
基于Chrome Developer Tools的JavaScript开发与调试 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • 使用Eclipse Memory Analyzer分析JVM堆Dump
  • Tomcat知识集锦
  • 使用Oracle Java Mission Control监控JVM运行状态
  • Tomcat6作为Windows服务时的JAVA_OPTS设置
  • Hibernate知识集锦

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2