jvm调优

1,jvm常用参数

可以通过java -XX:+PrintFlagsFinal命令查看jvm各参数在当前机器上的默认值,

或者jinfo -flag MetaspaceSize pid查看指定进程的参数的值:

参数 功能 默认值
-Xms 初始堆大小 物理内存1/64
-Xmx 最大堆大小 物理内存1/4
-Xmn 年轻代大小
(NewSize与MaxNewSize设为一致)
堆的1/3
-XX:MetaspaceSize 元数据区大小 20.8M
-XX:MaxMetaspaceSize 元数据区最大值 4g
-XX:NewSize 年轻代默认大小 2m
-XX:MaxNewSize 年轻代最大值(根据 NewRatio计算)
-Xss 每个线程的堆栈大小 1M
-XX:NewRatio 新生代和老年代比值 2
-XX:SurvivorRatio Eden与Survivor的占用比例。
默认值8表示survivor占用2/8(两个survivor),Eden占用6/8。
8
-XX:+AggressiveOpts 启用JVM开发团队最新的调优成果。
例如编译优化,偏向锁,并行年老代收集等。
默认不启用
--XX:MaxHeapFreeRatio 空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。 70
--XX:MinHeapFreeRatio 空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制。 40
-XX:-DisableExplicitGC 禁止在运行期显式地调用 System.gc()。
开启该选项后,GC的触发时机将由Garbage Collector全权掌控。
默认不启用
-XX:-UseConcMarkSweepGC 启用CMS低停顿垃圾收集器 默认不启用
-XX:+UseParNewGC 新生代并行回收 默认不启用
-XX:+ScavengeBeforeFullGC 在Full GC前触发一次Minor GC 默认启用
-XX:ParallelGCThreads 并行收集器线程数 如果cpu线程数<=8则使用cpu线程数,否则增加5/8的线程总数
-XX:ConcGCThreads 并发垃圾收集器使用的线程数量 XX:ParallelGCThreads/4
-XX:+UseG1GC 使用g1回收器 默认不启用
-XX:MaxGCPauseMillis 最大GC停顿时间,这是个软目标,JVM将尽可能(但不保证)停顿小于这个时间 200ms
-XX:InitiatingHeapOccupancyPercent 启动并发GC周期时的堆内存占用百分比 45
-XX:G1ReservePercent 设置堆内存保留为假天花板的总量,以降低提升失败的可能性 10
-XX:G1HeapRegionSize 使用G1时Java堆会被分为大小统一的的区(region)。此参数可以指定每个heap区的大小. 默认值将根据 heap size 算出最优解. 最小值为 1Mb,最大值为 32Mb.
-XX:+CMSScavengeBeforeRemark 在CMS GC前启动一次ygc,目的在于减少old gen对ygc gen的引用,降低remark时的开销-----一般CMS的GC耗时 80%都在remark阶段 默认不启用
-XX:CMSInitiatingOccupancyFraction 堆内存使用达到70%时启动cms gc 70
-XX:+UseCMSInitiatingOccupancyOnly 只是用设定的回收阈值(XX:CMSInitiatingOccupancyFraction),如果不指定,JVM仅在第一次使用设定值,后续则自动调整 默认不启用
XX:+AlwaysPreTouch 当JVM初始化时预先对Java堆进行预先摸底(Pre-touch),堆的每个页初始化时满足需求,而不是应用执行时递增。 默认不启用

2,jvm调优(g1)

由于java后续版本g1是主流,所以调优针对的是g1。

2.1,堆的大小上限一般不要超过32gb

在堆中,32位的对象引用占4个字节,而64位的对象引用占8个字节。也就是说,64位的对象引用大小是32位的2倍。java6之后支持-XX:+UseCompressedOops开启指针压缩,默认开启。

Enables the use of compressed pointers (object references represented as 32 bit offsets instead of 64-bit pointers) for optimized 64-bit performance with Java heap sizes less than 32gb.

指针压缩原理:

? 32位内最多可以表示4GB,64位地址分为堆的基地址+偏移量,当堆内存<32GB时候,在压缩过程中,把偏移量/8后保存到32位地址。在解压时再把32位地址放大8倍,所以启用CompressedOops的条件是堆内存要在4GB*8=32GB以内。

? 如果GC堆大小在4G以上32G以下,则启用UseCompressedOop ,如果GC堆大小大于32G,压指失效,使用原来的64位。

所以正常情况下,堆内存最大不要超过32gb。

2.2,使用g1的时候不能设置年轻代的大小(-Xmn)

在使用g1回收器的时候如果同时设置了-Xmn参数,也就是指定了年轻代的大小,那么这将影响g1的回收,因为一旦设置了年轻代的大小,那么g1将无法动态调整堆的各区间的大小,同时g1的最大暂停时间目标将不再起作用。与此同时,最大暂停时间(-XX:MaxGCPauseMillis)只是个期望值,g1无法绝对保证,而且设置最大暂停时间的值不能用平均响应时间来设置,应该用上限响应时间或者接近上限响应时间的值来设置。

2.3,解决回收过程中的转移失败(Evacuation Failure)

? gc日志中常可以看到"evacuation failure","to-space exhausted","to-space overflow", "promotion failure"之类的输出,这是由于g1在回收的过程中无法找到空闲空间放置存活对象,这种情况称为Evacuation Failure(类比cms中的晋升失败):

924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted),0.1957310 secs]
924.897:[GC pause (G1 Evacuation Pause) (mixed) (to-space overflow),0.1957310 secs]

? 这个易导致full gc,而g1中的full gc是Serial收集器,这会导致秒级的暂停时间,所以在g1中要尽量避免出现full gc。针对此情况可以做一下调整:

  1. 减少InitiatingHeapOccupancyPercent参数的值(默认45)提前启动标记周期,但同时也会增加GC发生频率;
  2. 增加ConcGCThreads参数的值来增加并发标记的线程数目,提高gc的效率,但同时也会占用更多工作线程的资源;
  3. 增加 -XX:G1ReservePercent参数的值(并相应增加总的堆大小),为"目标空间"(to-space)增加预留内存量。

2.4,巨型对象分配(Humongous Allocation)

? 对于 G1 GC,任何超过区域(G1HeapRegionSize)一半大小的对象都被视为“巨型对象”。此类对象直接被分配到老年代中的“巨型区域”。这些巨型区域是一个连续的区域集。StartsHumongous 标记该连续集的开始,ContinuesHumongous 标记它的延续。

? g1只会在标记周期结束的时候清理巨型对象,或者在full gc的时候其不可达。巨型对象不会移动,即使是full gc时也是如此,这会过早的减慢full gc的效率。

由于每个 StartsHumongous 和 ContinuesHumongous 区域集只包含一个巨型对象,所以没有使用巨型对象的终点与上个区域的终点之间的空间(即巨型对象所跨的空间)。如果对象只是略大于堆区域大小的倍数,则此类未使用的空间可能会导致堆碎片化。

巨型对象分配日志示例:

280.008: [G1Ergonomics (Concurrent Cycles) request concurrent cycle initiation,reason: occupancy higher than threshold,occupancy: 62344134656 bytes,allocation request: 46137368 bytes,threshold: 42520176225 bytes (45.00 %),source: concurrent humongous allocation]

如果巨型分配导致连续的并发周期,并且此类分配导致老年代碎片化,可以增加 -XX:G1HeapRegionSize,这样一来,之前的巨型对象就不再是巨型对象了,而是采用常规的分配路径,或者分析程序本身以减少此类对象的产生。-XX:G1HeapRegionSize,其值为2的次幂,最小值为 1mb,最大值为 32mb。

2.5,垃圾回收算法CMS和G1的选择

程序调优的两个目标特点:

指标 定义
响应能力 响应能力又或者延时(Latency)指系统对任务的响应速度,比如有人机交互的系统(gui程序,web界面)。响应能力优先的系统,对系统长时间的卡顿是无法接受的。
吞吐量 吞吐量(Throughput)指系统单位时间内处理任务的能力,吞吐量优先的系统,更需要考虑的是系统处理大量任务的效率,至于单次任务的效率无足轻重,所以卡顿是可以接受的,只要整体效率有保障。

响应能力和吞吐量是衡量系统性能的两个重要指标,这两个指标并不是绝对对立的,最终系统的表现取决于系统的瓶颈。

类别 优点 缺点 适用场景
CMS 并发收集、低停顿 对cpu资源敏感;
无法处理浮动垃圾;
容易出现内存空间碎片;
对响应时间敏感,cpu资源丰富,
追求服务的响应速度,
相应牺牲服务的吞吐量。
G1 无内存空间碎片的问题;
可预测的停顿;
配置少,可动态调优至最优配置
g1触发full gc时会退化使用Serial收集器进行回收,导致秒级的暂停时间 面向服务端,适用于多核,大内存的服务端系统。
实现高吞吐量的同时,尽可能满足gc暂停时间的要求

2.6 jvm参数示例

### g1
-server
-Xms10g
-Xmx10g
-XX:+AlwaysPreTouch
-XX:+UseG1GC
-XX:+ScavengeBeforeFullGC
-XX:+DisableExplicitGC
### cms
-server
-Xms10g
-Xmx10g
-XX:+AlwaysPreTouch
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenSweepingEnabled
-XX:+ScavengeBeforeFullGC
-XX:+CMSScavengeBeforeRemark
-XX:+DisableExplicitGC

3,jvm 日志

3.1 gc日志参数

参数 功能
-verbose:gc 输出一些详细的gc信息(等同 -XX:+PrintGC),
-XX:+PrintGC后续版本弃用
-XX:+PrintGCDetails 输出gc的详细信息
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式)
-XX:+PrintAdaptiveSizePolicy 打印自适应收集的大小,默认关闭
-XX:+UseGCLogFileRotation 打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数,并且开启后默认的文件数和文件大小不受限制
-XX:NumberOfGCLogFiles 设置滚动日志文件的个数,必须大于1
-XX:GCLogFileSize 设置滚动日志文件的大小,默认8k
-Xloggc:[file] 将gc信息输出到单独的日志文件,示例: Xloggc:/path/to/gc/logs/log.txt

3.2 gc日志解读

  • cms日志示例:
[GC [ParNew: 471013K->44702K(471872K),0.0151339 secs] 1092059K->673523K(2044736K),0.0154045 secs] [Times: user=0.18 sys=0.04,real=0.02 secs]

[Full GC [PSYoungGen: 1403K->33K(912504K)] [ParOldGen: 8K->1261K(1048576K)] 1411K->1261K(1926080K),[Metaspace: 3508K->3508K(1056768K)],0.0083870 secs] [Times: user=0.01 sys=0.00,real=0.01 secs]


各个指标对应的含义:
[GC类型(导致原因) [发生区域: gc前大小->gc后大小(总大小),gc占用时间] gc前堆大小->gc后堆大小(堆总大小),该内存区gc占用时间] [Times: 用户态耗时,内核态耗时,实际耗时(wall clock time)]

注意:Minor GC,Major GC均会导致STW

  • G1日志示例

    0.522: [GC pause (young),0.15877971 secs]

    ? 这是一个转移暂停,距离进程启动的0.522秒开始,所有被转移的是年轻代分区,一共花费了0.15877971秒。

    ? 转移暂停也可以是混合的,比如:1.730:[GC pause (mixed),0.32714353 secs]此时分区包含所有的年轻代分区和部分老年代分区。

    [Parallel Time: 157.1 ms]
       并行GC Worker线程的总耗时,下面缩进部分是worker线程的子任务
          [GC Worker Start (ms):  522.1  522.2  522.2  522.2 
          每个worker线程的启动时间(距离jvm启动的时间)
           Avg: 522.2,Min: 522.1,Max: 522.2,Diff:   0.1] 
          所有线程启动时间的avg,min,max,diff(下同,不赘述)
          [Ext Root Scanning (ms):  1.6  1.5  1.6  1.9 
          每个线程扫描Roots(全局变量,寄存器,线程栈,vm数据结构)的时间
        Avg:   1.7,Min:   1.5,Max:   1.9,Diff:   0.4] 同上
          [Update RS (ms):  38.7  38.8  50.6  37.3 
          每个线程更新Remember Set(RSet)时间,RSet保存引用
           Avg:  41.3,Min:  37.3,Max:  50.6,Diff:  13.3]
             [Processed Buffers : 2 2 3 2
              Sum: 9,Avg: 2,Min: 2,Max: 3,Diff: 1]
          [Scan RS (ms):  9.9  9.7  0.0  9.7 
          扫描RSet的时间,每个分区的RSet包含指向分区的Card。这个阶段扫描CSet集合中所有指向分区的Card。
           Avg:   7.3,Min:   0.0,Max:   9.9,Diff:   9.9]
          [Object Copy (ms):  106.7  106.8  104.6  107.9 
          拷贝CSet集合里面所有分区存活对象到另一个分区的时间。
           Avg: 106.5,Min: 104.6,Max: 107.9,Diff:   3.3]
          [Termination (ms):  0.0  0.0  0.0  0.0
           Avg:   0.0,Max:   0.0,Diff:   0.0]
             [Termination Attempts : 1 4 4 6
              Sum: 15,Avg: 3,Min: 1,Max: 6,Diff: 5]
          [GC Worker End (ms):  679.1  679.1  679.1  679.1 
          每个线程的停止时间
           Avg: 679.1,Min: 679.1,Max: 679.1,Diff:   0.1]
          [GC Worker (ms):  156.9  157.0  156.9  156.9 
          每个线程的耗时
           Avg: 156.9,Min: 156.9,Max: 157.0,Diff:   0.1]
          [GC Worker Other (ms):  0.3  0.3  0.3  0.3 
          每个线程执行除了上面操作的其他任务的耗时
           Avg:   0.3,Min:   0.3,Max:   0.3,Diff:   0.0]
       [Clear CT:   0.1 ms] 
       串行清除Card Table的时间
    [Other:   1.5 ms]
          [Choose CSet:   0.0 ms] 为CSet选择Region的时间
          [Ref Proc:   0.3 ms] 处理对象引用的时间
          [Ref Enq:   0.0 ms] 引用入ReferenceQueues队列的时间
          [Free CSet:   0.3 ms] 释放CSet时间
       [Eden: 12M(12M)->0B(10M) Survivors: 0B->2048K Heap: 13M(64M)->9739K(64M)]
       Eden在回收之前容量和占用都是12MB,回收之后占用为0,容量为13MB(有新的分区加入Eden)。
       Survivor回收之后,占用从0变到2048KB,整个堆在回收之前占用和容量是14MB和64MB,回收之后是9739KB和64MB。
     [Times: user=0.59 sys=0.02,real=0.16 secs]

3.3 gc日志可视化

可以使用gcviewer对gc日志进行可视化,这样可以更直观的观察和分析gc日志,其地址为:

https://github.com/chewiebug/GCViewer

参考链接:

https://blog.csdn.net/Dax1n/article/details/77163540

https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

https://juejin.im/post/5c4c8ad9f265da6179752b03

https://www.cnblogs.com/happyflyingpig/p/8918675.html

http://www.voidcn.com/article/p-aniwwiim-d.html

https://blog.51cto.com/14237164/2379588

https://www.oracle.com/technetwork/cn/articles/java/g1gc-1984535-zhs.html

http://www.raincent.com/content-85-4354-5.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


jinfo 命令可以用来查看 Java 进程运行的 JVM 参数,命令如下:[root@admin ~]# jinfo --helpUsage: jinfo [option] &lt;pid&gt; (to connect to running process) jinfo [option] &lt;executable &lt;core&gt; (to connect to a core file) jinfo [option] [serve
原文链接:https://www.cnblogs.com/niejunlei/p/5987611.htmlJava Virtual Machine Stacks,线程私有,生命周期与线程相同,描述的是Java方法执行的内存模型:每一个方法执行的同时都会创建一个栈帧(Stack Frame),由于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法的执行就对应着栈帧在虚拟机栈中的入栈,出栈...
java 语言, 开发者不能直接控制程序运行内存, 对象的创建都是由类加载器一步步解析, 执行与生成与内存区域中的; 并且jvm有自己的垃圾回收器对内存区域管理, 回收; 但是我们已经可以通过一些工具来在程序运行时查看对应的jvm内存使用情况, 帮助更好的分析与优化我们的代码;jps查看系统中有哪些java进程jps 命令类似与 linux 的 ps 命令,但是它只列出系统中所有的 Java 应用程序。 通过 jps 命令可以方便地查看 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息
1.jvm的简单抽象模型:  2.类加载机制     双亲委派模型是为了防止jdk核心类库被篡改,如果需要打破可以重写Classloader.loadClass方法。r 双亲委派模型:一个类加载器收到一个类的加载请求,他会先判断自身是否已存在该类,如果不存在上抛给上一级类加载器ClassLoad
堆外内存JVM启动时分配的内存,称为堆内存,与之相对的,在代码中还可以使用堆外内存,比如Netty,广泛使用了堆外内存,但是这部分的内存并不归JVM管理,GC算法并不会对它们进行回收,所以在使用堆外内存时,要格外小心,防止内存一直得不到释放,造成线上故障。堆外内存的申请和释放JDK的ByteBuffe
1.springboot和tomcat2.springcloud的请求如何通过网关鉴权?3.springmvc启动时组件的加载顺序?4.mybatis如何同时更新三条记录5.hibernate实现级联更新6.一个web程序应用程序启动时的加载流程7.如何向www.baidu.com地址发出请求时,并获取相应?8.???9.谈谈你对tcp/iptelnetudp协
堆设置-Xms256M:初始堆大小256M,默认为物理内存的1/64-Xmx1024M:最大堆大小1024M,默认为物理内存的1/4,等于与-XX:MaxHeapSize=64M-Xmn64M:年轻代大小为64M(JDK1.4后支持),相当于同时设置NewSize和MaxNewSize为64M-XX:NewSize=64M:初始年轻代大小-XX:MaxNewSize=256M:最大年轻代大小(默认
一.概述收集算法(JVM之垃圾回收-垃圾收集算法)是内存回收的抽象策略,垃圾收集器就是内存回收的具体实现。JVM规范对于垃圾收集器的应该如何实现没有任何规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器差别较大,这里只看HotSpot虚拟机。就像没有最好的算法一样,垃圾收集器
Java中的堆是JVM所管理的最大的一块内存空间,主要用于存放各种类的实例对象,如下图所示: 在Java中,堆被划分成两个不同的区域:新生代(Young)、老年代(Old)。新生代(Young)又被划分为三个区域:Eden、S0、S1。 这样划分的目的是为了使JVM能够更好的管理堆内存中的对象,包
JVM深入理解JVM(4)——如何优化JavaGC「译」 PostedbyCrowonAugust21,2017本文翻译自SangminLee发表在Cubrid上的”BecomeaJavaGCExpert”系列文章的第三篇《HowtoTuneJavaGarbageCollection》,本文的作者是韩国人,写在JDK1.8发布之前,虽然有些地
 JVM深入理解JVM(2)——GC算法与内存分配策略 PostedbyCrowonAugust10,2017说起垃圾收集(GarbageCollection,GC),想必大家都不陌生,它是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如Scala等)程序员在提升开
运行时数据区  线程独有本地方法栈、虚拟机栈、程序计数器这些与线程对应的数据区会随着线程开始和结束创建和销毁  整体公有元数据区(又称方法区)、堆区会随着虚拟机启动而创建,随着虚拟机退出而销毁 
java整个堆大小设置:Xmx和Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍。永久代PermSize和MaxPermSize设置为老年代存活对象的1.2-1.5倍年轻代Xmx的设置为老年代存活对象的1-1.5倍老年代的内存大小设置为老年代存活对象的2-3倍BTW: Sun官方建议年轻代
栈顶缓存(Top-of-StackCashing)技术基于栈式架构得虚拟机所使用的零地址指令更加紧凑,但完成一项操作的时候必然使用更多的入栈和出栈指令,这同时也就意味着将需要更多的指令分派次数和内存读写次数 由于操作数是存储在内存重的,因此频繁地执行内存读/写操作必然影响速度。 综上
自用。同样的代码在不同的平台生成的机器码是不一样的,为什么java代码生成的字节码文件,能在不同的平台运行?因为不同版本的jdk里面的虚拟机会屏蔽不同操作系统在底层硬件与指令上的区别。栈:线程栈,局部变量存放栈内存区域。线程(分配一个栈)运行分配栈将局部变量放入内存。怎么放:栈
jconsole监控:1.java启动命令加上参数java-Djava.rmi.server.hostname=172.16.17.247-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=2099-Dcom.sun.management.jmxremote.authenticate=false-Dcom.sun.management.jmxremote.ssl=false -XX:+Unlock
类加载器分类publicclassStackStruTest{publicstaticvoidmain(String[]args){//对用户自定义个类来说:默认使用系统类加载器进行加载-----AppClassLoaderClassLoaderclassLoader=StackStruTest.class.getClassLoader();System.out.p
堆体系结构一个JVM实例只存在一个堆内存,堆内存的大小是可调节的。类加载器读取类文件后,需要把类、方法、常量、变量放在堆内存中,保存所有引用类型的真实信息,以方便执行器指向,堆内存分为三个部分:年轻代、老年代、永久代。Java7之前,堆内存在逻辑上分为:年轻代、老年代、永久代。物
JVM深入理解JVM(5)——虚拟机类加载机制 PostedbyCrowonAugust21,2017在Class文件中描述的各种信息,最终都需要加载到虚拟机中之后才能运行和使用。而虚拟机中,而虚拟机如何加载这些Class文件?Class文件中的信息进入到虚拟机中会发生什么变化?本文将逐步解答这
保存(持久化)对象及其状态到内存或者磁盘Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在