JVM 调优 —— 新生代 Survivor 空间不足

零. 新生代调优规律

增大新生代空间, Minor GC 频率减少, Minor GC 时间上升。 减少新生代空间, Minor GC 频率上升, Minor GC 时间下降

一. 新生代典型问题

先看一段 GC 日志:新生代使用 ParNew, 老年代使用 CMS

{Heap before GC invocations=0 (full 0):
 par new generation   total 943744K, used 838912K [0x0000000757000000, 0x0000000797000000, 0x0000000797000000)
  eden space 838912K, 100% used [0x0000000757000000, 0x000000078a340000, 0x000000078a340000)
  from space 104832K,   0% used [0x000000078a340000, 0x000000078a340000, 0x00000007909a0000)
  to   space 104832K,   0% used [0x00000007909a0000, 0x00000007909a0000, 0x0000000797000000)
 concurrent mark-sweep generation total 1560576K, used 0K [0x0000000797000000, 0x00000007f6400000, 0x00000007f6400000)
 concurrent-mark-sweep perm gen total 159744K, used 38069K [0x00000007f6400000, 0x0000000800000000, 0x0000000800000000)
2016-01-19T14:15:34.532+0800: 13.812: [GC2016-02-19T14:15:34.532+0800: 13.812: [ParNew
Desired survivor size 53673984 bytes, new threshold 1 (max 6)
- age   1:   55521392 bytes,   55521392 total
: 838912K->54474K(943744K), 0.0914620 secs] 838912K->54474K(2504320K), 0.0916240 secs] [Times: user=0.67 sys=0.06, real=0.09 secs]
Heap after GC invocations=1 (full 0):
 par new generation   total 943744K, used 54474K [0x0000000757000000, 0x0000000797000000, 0x0000000797000000)
  eden space 838912K,   0% used [0x0000000757000000, 0x0000000757000000, 0x000000078a340000)
  from space 104832K,  51% used [0x00000007909a0000, 0x0000000793ed2ae0, 0x0000000797000000)
  to   space 104832K,   0% used [0x000000078a340000, 0x000000078a340000, 0x00000007909a0000)
 concurrent mark-sweep generation total 1560576K, used 0K [0x0000000797000000, 0x00000007f6400000, 0x00000007f6400000)
 concurrent-mark-sweep perm gen total 159744K, used 38069K [0x00000007f6400000, 0x0000000800000000, 0x0000000800000000)
}
{Heap before GC invocations=1 (full 0):
 par new generation   total 943744K, used 893386K [0x0000000757000000, 0x0000000797000000, 0x0000000797000000)
  eden space 838912K, 100% used [0x0000000757000000, 0x000000078a340000, 0x000000078a340000)
  from space 104832K,  51% used [0x00000007909a0000, 0x0000000793ed2ae0, 0x0000000797000000)
  to   space 104832K,   0% used [0x000000078a340000, 0x000000078a340000, 0x00000007909a0000)
 concurrent mark-sweep generation total 1560576K, used 0K [0x0000000797000000, 0x00000007f6400000, 0x00000007f6400000)
 concurrent-mark-sweep perm gen total 159744K, used 53249K [0x00000007f6400000, 0x0000000800000000, 0x0000000800000000)
2016-01-19T14:15:41.943+0800: 21.222: [GC2016-02-19T14:15:41.943+0800: 21.223: [ParNew
Desired survivor size 53673984 bytes, new threshold 1 (max 6)
- age   1:  107256200 bytes,  107256200 total
: 893386K->104832K(943744K), 1.2389070 secs] 893386K->210614K(2504320K), 1.2391870 secs] [Times: user=2.89 sys=0.35, real=1.24 secs]
Heap after GC invocations=2 (full 0):
 par new generation   total 943744K, used 104832K [0x0000000757000000, 0x0000000797000000, 0x0000000797000000)
  eden space 838912K,   0% used [0x0000000757000000, 0x0000000757000000, 0x000000078a340000)
  from space 104832K, 100% used [0x000000078a340000, 0x00000007909a0000, 0x00000007909a0000)
  to   space 104832K,   0% used [0x00000007909a0000, 0x00000007909a0000, 0x0000000797000000)
  concurrent mark-sweep generation total 1560576K, used 105782K [0x0000000797000000, 0x00000007f6400000, 0x00000007f6400000)
 concurrent-mark-sweep perm gen total 159744K, used 53249K [0x00000007f6400000, 0x0000000800000000, 0x0000000800000000)
}

可以明显看出上述 GC 日志包含两次 Minor GC。 注意到第二次 Minor GC 的情况, 日志打出 "Desired survivor size 53673984 bytes", 但是却存活了 "- age   1:  107256200 bytes,  107256200 total" 这么多。 可以看出明显的新生代的 Survivor 空间不足。正因为 Survivor 空间不足,
那么从 Eden 存活下来的和原来在 Survivor 空间中不够老的对象占满 Survivor 后, 就会提升到老年代, 可以看到这一轮 Minor GC 后老年代由原来的 0K 占用变成了 105782K 占用, 这属于一个典型的 JVM 内存问题, 称为 "premature promotion"(过早提升)。

"premature promotion” 在短期看来不会有问题, 但是经常性的 "premature promotion”, 最总会导致大量短期对象被提升到老年代, 最终导致老年代空间不足, 引发另一个 JVM 内存问题 “promotion failure”(提升失败: 即老年代空间不足以容乃 Minor GC 中提升上来的对象)。  “promotion failure” 发生就会让 JVM
进行一次 CMS 垃圾收集进而腾出空间接受新生代提升上来的对象, CMS 垃圾收集时间比 Minor GC 长, 导致吞吐量下降、 时延上升, 将对用户体验造成影响。

二. 新生代调优建议

对于上述的新生代问题, 如果服务器内存足够用, 建议是直接增大新生代空间(如 -Xmn)。如果内存不够用, 则增加 Survivor 空间, 减少 Eden 空间, 但是注意减少 Eden 空间会增加 Minor GC 频率, 要考虑到应用对延迟和吞吐量的指标最终是否符合。

要增大多少 Survivor 空间? 需要观察多次 Minor GC 过程, 看 Minor GC 后存活下来的对象大小, 最终确定 Survivor 的合适大小。 整个调优过程可能需要几次调整, 才能找到比较合适的值。调整几次后, 如果内存还是不够用, 就要需要考虑增大服务器内存, 或者把负载分担到更多的 JVM 实例上。

Survivor 空间计算公式: survivor 空间大小 = -Xmn[value] / (-XX:SurvivorRatio=<ratio> + 2)

时间: 2024-08-04 08:55:33

JVM 调优 —— 新生代 Survivor 空间不足的相关文章

JVM调优-新生代

JAVA虚拟机新生代,包括eden space+2个survivor空间. 新生代用来存放新近创建的对象,新生代的特点是对象更新速度快,在短时间内产生大量的"死亡对象".对年轻代的垃圾回收称作次级回收 (minor gc) 1.新生代与次级回收 新生代分为三个区域,  一个eden spac , 2个大小相同的survivor,  应用程序只能使用一个eden和一个survivor, 当发生初级垃圾回收的时候,gc挂起程序, 然后将eden和survivorA中的存活对象复制到另外一个

JVM调优经验分享

前言 一.JVM调优知识背景简介 二.JVM调优参数简介 三.JVM调优目标 四.JVM调优经验 结束语 <br/> 本次分享探讨的JVM调优是指server端运行的JVM调优,适应版本为[1.6– 1.7], 不涉及最新的1.8版本. 假设线程池.连接池.程序代码等都已经做过优化,效果(系统吞吐量.响应性能)仍然不理想,我们就可以考虑JVM调优了. <br/> 一. JVM调优知识背景简介 1.堆与栈的概念 堆和栈是程序运行的关键:栈是运行时的单位,而堆是存储的单位. 栈解决程序

JVM调优及参数设置

(1)参数 -Xms:初始堆大小 -Xmx :最大堆大小 此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存 -Xmn :年轻代大小 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8. -XX:NewSize:设置年轻代大小 -XX:MaxNewSize:年轻代最大值 -XX:NewRatio 年老代与年轻代的比值 -XX:SurvivorRat

jvm 调优

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁.根据<Java虚拟机规范(第2版)>的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域,虚拟机栈.本地方法栈.程序计数器为线程私有部分,虚拟机堆.方法区为共享部分),见下图: 程序计数器 程序计数器(Program Counter Register)是一块较小的内存

JVM调优知识

一.Java应用服务器 Tomcat.Nginx.Resin.等多种应用服务器,虽然JVM做为容器,提供的是一个Java Web的运行时环境,以支持Servlet/JSP等等这些内容的运行但是我们都很清楚,其本质上是还是一个Java应用程序.现在有哪些java应用服务器呢?商业的有BEA Weblogic Server.IBM Websphere Application Server.Oracle Application Server.Sybase EAServer.免费开源的java应用服务器

《JVM调优实战-理论篇》

1 理论篇1.1 多功能养鱼塘-JVM内存大鱼塘O(可分配内存): JVM可以调度使用的总的内存数,这个数量受操作系统进程寻址范围.系统虚拟内存总数.系统物理内存总数.其他系统运行所占用的内存资源等因素的制约.小池塘A(堆内存):JVM运行时数据区域,它为类实例和数组分配的内存.堆可以是固定大小的也可以是可变大小的.其中 Heap = {Old + NEW = { Eden , from, to } }.小池塘B(非堆内存):包括所有线程之间共享的一个方法区域和JVM为优化或内部处理所分配的内存

Java虚拟机(五):JVM调优-命令篇

运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer等等,但是在生产环境出现问题的时候,一方面工具的使用会有所限制,另一方面喜欢装X的我们,总喜欢在出现问题的时候在终端输入一些命令来解决.所有的工具几乎都是依赖于jdk的接口和底层的这些命令,研究这些命令的使用也让我们更能了解jvm构成和特性. Sun JDK监控和故障处理命令有jps jstat j

生产环境下JVM调优参数的设置实例

JVM基础:生产环境参数实例及分析 原始配置: -Xms128m -Xmx128m -XX:NewSize=64m -XX:PermSize=64m -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=78 -XX:ThreadStackSize=128k-Xloggc:logs/gc.log -Dsun.rmi.dgc.server.gcInterval=3600000 -Dsun.rmi.dgc.client.gcInterv

JVM调优常用参数和注意点备忘录

本文主要是工作过程中总结的一些jvm调优的参数和注意的地方,作为一个备忘录,先占个坑,有时间在来细化具体的实例. gc日志是覆盖的方式如果文件名字固定会导致上一次被覆盖可以采用这个-Xloggc:backv2_gc_%t.log jinfo可以动态修改java -XX:+PrintFlagsFinal -version|grep manageable这些参数 打印java可配置的非稳定参数:java -XX:+PrintFlagsFinal ,输出的信息中 ":=" 表明了参数被用户或