JVM调优

 目录

jvm参数常用配置

JVM性能调优监控工具(jdk自带)

jvm垃圾收集器

GC机制(分代收集)

jvm调优案例


jvm参数常用配置

1. 堆设置

  • -Xms:初始堆大小
  • -Xmx:最大堆大小
  • -XX:NewSize=n:设置年轻代大小
  • -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3
  • -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
  • -XX:MaxPermSize=n:设置持久代大小

2. 收集器设置

  • -XX:+UseSerialGC:设置串行收集器
  • -XX:+UseParallelGC:设置并行收集器
  • -XX:+UseParalledlOldGC:设置并行年老代收集器
  • -XX:+UseConcMarkSweepGC:设置并发收集器
  • -XX:+UseParNewGC对年轻代采用多线程并行回收

3. 垃圾回收统计信息

  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintGCTimeStamps
  • -Xloggc:filename

 

JVM性能调优监控工具(jdk自带)

  • jps:用来输出JVM中运行的进程状态信息。
  • jstack:用于生成虚拟机当前时刻的线程快照。当cpu高怀疑有死循环或者死锁时可以使用。

  • jstat:监视虚拟机各种运行状态信息,可以显示本地或者是远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。可以使用此工具查看gc情况,分析是否有内存泄漏。

  • jmap:生成虚拟机的堆内存转储快照。

  • JVisualVM:是一种集成了多个JDK命令行工具的可视化工具,它囊括的命令行工具包括jstat,JConsole,jstack,jmap和jinfo,可以查看cpu、内存、类、线程的情况,查看虚拟机运行参数,可以导出堆dump文件,也可以分析dump文件,还可以安装Visual GC插件查看gc情况。

 

jvm垃圾收集器

  • serial是默认的新生代收集器,但会stop the world带来不良体验。
  • parnew是多线程的serial,公司目前使用,多核下优于serial。
  • parallel scavenge关注吞吐量。
  • serial old
  • parallel old
  • cms注重最短回收停顿时间,思想体现在回收线程与用户线程并行。
  • g1最先进但尚未成熟,思想是将堆划分为多个块,化整为零,避免全堆扫描,但由于各块之间对象互相引用,所以具体实现特别复杂。

"高吞吐量"和"低暂停时间"是一对相互竞争的目标(矛盾)。应用程序在GC期间必须停止(或者仅在GC的特定阶段,这取决于所使用的算法),然而这会增加额外的线程调度开销:直接开销是上下文切换,间接开销是因为缓存的影响。 加上JVM内部安全措施的开销,这意味着GC及随之而来的不可忽略的开销,将增加GC线程执行实际工作的时间。 因此我们可以通过尽可能少运行GC来最大化吞吐量。然而,仅仅偶尔运行GC意味着每当GC运行时将有许多工作要做,因为在此期间积累在堆中的对象数量很高。 单个GC需要花更多时间来完成, 从而导致更高的平均和最大暂停时间。 因此,考虑到低暂停时间,最好频繁地运行GC以便更快速地完成。 这反过来又增加了开销并导致吞吐量下降,我们又回到了起点。综上所述,在设计(或使用)GC算法时​​,我们必须确定我们的目标:一个GC算法​​只可能针对两个目标之一(即只专注于最大吞吐量或最小暂停时间),或尝试找到一个二者的折衷。在注重吞吐量和cpu资源敏感的场合优先考虑parallel scavenge和parallel old组合。parnew和cms组合优先考虑与用户交互较多的场景,希望系统停顿时间最短,注重服务的响应速度,如常见WEB、B/S系统的服务器上的应用。

GC机制(分代收集)

新生代采用标记复制算法,老年代采用标记清除(cms)或标记整理算法。

对象首先在eden区分配,当Eden区没有足够空间进行分配时,虚拟机会发起一次 Minor GC,把存活的对象复制到to space区域,如果to space区域不够,则利用担保机制进入老年代区域。

对象进入老年代的方法:

  • 大对象直接进入老年代,可以指定阈值。
  • 长期存活的对象进入老年代。
  • 空间分配担保(eden区放不下,触发young gc,eden区存活对象又大于survivor区,所以通过分配担保提前转移到老年代)。
  • 同龄对象总和大于survivor空间的一半也能进老年代。

GC触发时机:

  • Minor GC触发条件:eden区满时,触发MinorGC。即申请一个对象时,发现eden区不够用,则触发一次MinorGC。在MinorGC时,会把存活的对象复制到to space区域,如果to space区域不够,则利用担保机制进入老年代区域。
  • Full GC触发条件:老生代空间不够分配新的内存、System.gc()、通过Minor GC后进入老年代的平均大小大于老年代的可用内存、Metaspace空间不足

jvm调优案例

问题:新部署的测试环境卡顿

使用gc viewer分析日志发现:

  • full gc非常多,比例超过minor gc,导致卡顿

使用jinfo或者visualvm观察jvm配置信息:

  • 发现其使用的垃圾收集器是parallel scavenge + serial old
  • -XX:MaxTenuringThreshold=0  经过多少次minor gc 后进入年老代,设置为0的话直接进入年老代,这是不太合理的,正常应该在年轻代多呆一段时间,真正需要到年老代的才转过去。默认为15。
  • -XX:SurvivorRatio=100  年轻代中eden和一块suvivor区的空间比例,这里设置成100有问题,新生代和老年代的大小都是512M,suvivor区空间大概为5M,一次minor gc后基本都转到年老代了,年轻代没有起到过滤作用

通过分析可以发现:由于survivor区内存和老年代晋升年龄设置不合理,导致新生代没有起到过滤作用,不常用的对象也进入了老年代,而且 serial old是单线程收集器,导致了卡顿问题。因此我们将收集器改为parnew + cms(最短暂停时间)、晋升年龄-XX:MaxTenuringThreshold=15、Eden区与Survivor区的比值-XX:SurvivorRatio=8。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值