对Tomcat 8.0进行JVM层面的优化(基于Oracle JDK 8)

Tomcat容器是运行在JVM上的, 其默认内存一般都很小(物理内存的1/64), 在实际生产环境中, 若不配置则会极大浪费服务器资源, 影像系统的性能. 可以通过调整JVM启动参数, 使得Tomcat拥有更好的性能.

对于JVM的优化主要有两个方面: 内存调优垃圾收集策略调优.

1 Tomcat的内存调优 1.1 Tomcat的内存占用

Tomcat 的运行内存 = Xmx(初始内存大小) + Perm Generation(JDK 7中的永久代大小) + Java应用创建的线程数 * 1MB.

Java 应用每创建一个线程, JVM 进程的内存中就会创建一个 Thread 对象, 同时也会在操作系统中创建一个真正的物理线程(参考JVM规范), 操作系统会在 Tomcat 的空闲内存中创建这个物理线程, 而不是在 JVM 的 Xmx 堆内存中创建.

在 JDK 1.4中, 默认的栈大小是256KB/线程, 但自 JDK 5(为了推广的方便, JDK 后续版本不再是1.x命名)开始, 默认的栈大小变为1M/线程. 举例: 如果系统剩余内存为400M, 则Java应用最多能创建400个可用线程.

结论: 要想创建更多的线程, 必须减少分配给JVM的最大内存.

1.2 内存配置相关参数 -server # JVM的server模式, 在多CPU服务器中性能可以得到更好地发挥. 默认为client. 配置server模式时要将其作为第一个参数. -Xmx4g # Java Heap的最大可用内存, 默认为物理内存的1/4(已在JDK 7下验证, 最大值为30638MB, 总内存126GB的23.75%). 在只运行Tomcar容器的服务器中, 建议设置为物理内存的50%~80%. -Xms4g # Java Heap的初始大小, 默认值为物理内存的1/64(已在JDK 7下验证, 内存126GB, 初始值为2GB). -Xss128k # 每个线程的Stack大小. 在相同物理内存下, 减小这个值能生成更多的线程, 但是操作系统对一个进程内的线程数是有限制的, 经验范围是3000~5000. -XX:NewRatio=4 # 设置新生代(包括Eden和两个Survivor区)与老年代的比值(除去持久代), 默认为2: 新生代与老年代所占比值为1:2, 新生代占整个堆栈的1/3. -XX:SurvivorRatio=4 # 设置新生代中Eden区与1个Survivor区的大小比值. 默认为8, 即Eden区占新生代的80%, 2个Survivor分别占新生代的10%. 设置为4, 则两个Survivor区与一个Eden区的比值为2:4, 一个Survivor区占整个新生代的1/6. -Xmn1024m # 设置Young Generation所占用的Java Heap大小为1g. 此值对系统性能影响较大, Sun官方推荐配置为整个堆的3/8(或Xmx的1/4~1/3左右). # 也可使用-XX:NewSize和-XX:MaxNewsize设置新生代的初始值和最大值. # 注意: -Xmn 与 -XX:NewSize、-XX:MaxNewSize 的优先级: -XX:NewRatio的值会被忽略. # 1. 高优先级: -XX:NewSize/-XX:MaxNewSize # 2. 中优先级: -Xmn, 等效与同时设置 -Xmn = -XX:NewSize = -XX:MaxNewSize 三者的值 # 3. 低优先级: -XX:NewRatio # -Xmn参数是在JDK 1.4 开始支持, 推荐使用之. -XX:NewSize=1g # 设置新生代的大小, 默认为1.25MB(已在JDK 7下验证). 若显示设置此值, 将使得NewRatio选项失效. -XX:OldSize=2g # 设置老年代的大小, 默认为5.1875MB(已在JDK 7下验证). -XX:PermSize=128m # JDK 7及以下版本适用: 设置Java Heap中永久代的初始大小, 默认为20.75MB(已在JDK 7下验证, client、server模式下均相同). -XX:MaxPermSize=256m # JDK 7及以下版本适用: 设置Java Heap中永久代的最大值. 默认为82.0MB(已在JDK 7下验证, client、server模式下均相同). -XX:MetaspaceSize=128m # JDK 8及以上版本适用: 初始元空间的大小, 默认为21MB(实际为20.79MB左右, 已验证). -XX:MaxMetaspaceSize=256m # JDK 8及以上版本适用: 最大元空间的大小. 默认无上限(在126GB物理内存的服务器中, 默认值为(2^44-1)MB, 已验证).

总结:

情形一: 如果不指定Xmx、Xms和NewSize、OldSize, 则系统将基于Xms=1/64总内存大小, 对各个Space按照NewRatio=2进行空间的分配, 此时NewSize与OldSize的默认大小将失效.

情形二: 如果指定了Xmx、Xms, 未指定NewSize、OldSize, 则系统将优先满足 NewRatio=2, 且OldSize+NewSize=Xms, 此时NewSize与OldSize的默认大小将失效.

结论: 除非显式指定NewSize与OldSize的值, 否则它们的默认配置一般都不会得到满足. 显式指定其中任一个, 另一个就会基于默认值, 并根据应用程序的消耗动态分配空间大小.

1.3 内存调优实践

JVM内存方面的调优, 需要在 ${TOMCAT_HOME}/bin/catalina.sh 文件中调整, 配置 JAVA_OPTS 变量即可. 在启动Tomcat时, 会执行catalina.sh中的脚本, 将 JAVA_OPTS 作为JVM的启动参数进行处理.

具体可参考如下配置(示例服务器配置: 126g的物理内存, 2个10核心20线程的物理CPU):

# 在文件最前面(即cygwin=false之前)设置, $JAVA_OPTS 的作用是保留原有的设置, 防止此次修改覆盖之前的设置 JAVA_OPTS="$JAVA_OPTS -Xmx96g -Xms96g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"

说明:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzsfz.html