目录
1 Tomcat 的内存调优
1.1 Tomcat 的内存占用
1.2 内存配置相关参数
1.3 内存调优实践
1.4 验证配置效果
2 GC 策略调优实践
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"
说明:
若不指定 Xmx, 即 Java Heap 的最大值, 程序启动时, JVM 会调整其大小以满足程序运行的需要. 每次调整时, 都会对堆进行一次完全垃圾收集(即 Full GC), 比较影响性能. 因此推荐明确指定 Xmx 的大小.
令 Xmx=Xms 会有更好地性能表现: 能避免 JVM 在每次垃圾收集后重新动态调节堆空间, 因为频繁伸缩堆大小将带来额外的性能消耗.
JVM 有 2 中模式: client 客户端模式 和 server 服务端模式 , 平时开发中使用的多是默认的 client 模式. 可通过命令行参数 -server 强制开启 server 模式. 两者之间的最大区别是, JVM 对 server 模式做了大量优化: 虽然 server 模式下应用程序启动较慢, 但在长时间运行下, 程序运行效率会明显高于 client 模式, 即 client 模式不适合需要长时间运行的项目 .
元空间的调优:
元空间的大小将受限于机器的内存的限制. 限制类的元数据的内存大小, 以避免出现虚拟内存切换以及本地内存分配失败.
如果可能出现类加载器泄漏, 应当配置此参数指定大小. 32 位机器上, 如果地址空间可能会被耗尽, 也应当配置此参数.
元空间的初始大小是 21M-- 这是 GC 的初始高水位线, 超过这个大小会进行 Full GC 来进行类的收集.
如果启动后 GC 过于频繁, 请将该值设置得大一些, 以便推迟 GC 的执行时间.
1.4 验证配置效果
- # 由于配置了环境变量, 在任意目录下使用 jps 及 jmap 命令, 即可调用相关工具:
- # 使用 jps 查看 Java 的所有进程
- [root@localhost ~]# jps
- 14308 Bootstrap
- 15620 Jps
- # 其中 Bootstrap 进程就是 Tomcat, 其进程号为 14308.
- # 通过 jmap 工具查看其内存相关配置
- [root@localhost ~]# jmap -heap 14308
- # 显示以下结果
- Attaching to process ID 24980, please wait...
- Debugger attached successfully.
- Server compiler detected.
- JVM version is 25.151-b12
- using thread-local object allocation.
- Parallel GC with 28 thread(s) # 默认使用并发 GC 策略
- Heap Configuration: # 堆的配置参数
- MinHeapFreeRatio = 0
- MaxHeapFreeRatio = 100
- MaxHeapSize = 103079215104 (98304.0MB) # 最大堆内存
- NewSize = 34359738368 (32768.0MB) # 新生代大小, 由于默认的 NewRatio=2, 所以是 1/3 的堆大小
- MaxNewSize = 34359738368 (32768.0MB)
- OldSize = 68719476736 (65536.0MB) # 老年代大小, 由于默认的 NewRatio=2, 所以是 2/3 的堆大小
- NewRatio = 2
- SurvivorRatio = 8
- MetaspaceSize = 21807104 (20.796875MB) # 元空间大小
- CompressedClassSpaceSize = 1073741824 (1024.0MB)
- MaxMetaspaceSize = 17592186044415 MB # 最大元空间大小
- G1HeapRegionSize = 0 (0.0MB)
- Heap Usage: # 堆的使用情况
- PS Young Generation
- Eden Space: # 新生代的伊甸区, 由于默认的 SurvivorRatio=8, 所以是 6/8 的 NewSize
- capacity = 25769803776 (24576.0MB)
- used = 9742123824 (9290.813278198242MB)
- free = 16027679952 (15285.186721801758MB)
- 37.80441600829363% used
- From Space: # 新生代的 From 区, 由于默认的 SurvivorRatio=8, 所以是 1/8 的 NewSize
- capacity = 4294967296 (4096.0MB)
- used = 0 (0.0MB)
- free = 4294967296 (4096.0MB)
- 0.0% used
- To Space: # 新生代的 To 区, 由于默认的 SurvivorRatio=8, 所以是 1/8 的 NewSize
- capacity = 4294967296 (4096.0MB)
- used = 0 (0.0MB)
- free = 4294967296 (4096.0MB)
- 0.0% used
- PS Old Generation # 老年代, 由于默认的 NewRatio=2, 所以是 2/3 的堆大小
- capacity = 68719476736 (65536.0MB)
- used = 254298704 (242.5181427001953MB)
- free = 68465178032 (65293.481857299805MB)
- 0.37005331832915545% used
- 23928 interned Strings occupying 3198312 bytes.
2 GC 策略调优实践
Tomcat 的 GC 策略一般都是与其内存参数一起配置的, 与应用复杂度相匹配的 GC 策略, 与服务器性能相适应的内存比例, 都将使得系统性能得到大幅提升.
GC 策略方面的调优, 也是在 ${TOMCAT_HOME}/bin/catalina.sh 文件中调整 -- 同样是配置 JAVA_OPTS 变量即可.
以 JDK 8,Tomcat 8 为例, 服务器内存为 126GB, 作出如下配置:
通过 Solr 集群大批量导入数据的应用中, Parallel GC 策略的暂停时间太长, 所以选择 CMS 收集器.
- # 下述配置各自独占一行, 要置于 "cygwin=false" 之前.
- # 配置内存
- JAVA_OPTS="-server -Xmx96g -Xms96g -Xmn35g -XX:OldSize=55g -Xss128k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
- # 配置 GC 策略
- JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15 -XX:CMSInitiatingOccupancyFraction=40 -XX:CMSFullGCsBeforeCompaction=0 -XX:+ExplicitGCInvokesConcurrent -XX:SoftRefLRUPolicyMSPerMB=0 -XX:MaxGCPauseMillis=100 -Xnoclassgc"
其中 Java Heap 的初始大小和最大大小均设置为 96g, 76% 的物理内存(以不超过 80% 为宜).
参考资料:
Tomcat 中 Java 垃圾收集调优
来源: https://www.cnblogs.com/shoufeng/p/9739525.html