You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用TLSv1.2运行Tomcat7/Java8时的Full GC性能问题

哥们,你碰到的这个问题我在Tomcat7+Java8的SSL环境里真的遇见过,结合你描述的现象和那片GC日志,咱们来一步步捋清楚:

核心现象复盘

咱们先把问题抓准:

  • 运行环境:启用SSL的Tomcat 7 + Java 8
  • 异常GC表现:首次触发Full GC时,老年代几乎没回收多少垃圾;但紧接着几分钟内第二次Full GC却能回收大量老年代对象,而且这种情况频繁发生,直接拖垮性能
  • 日志标记:GC日志里明确标了Full GC (Ergonomics),说明是JVM的自适应调优策略触发的GC

可能的根源分析

结合环境和现象,大概率是这几个原因:

  1. 软引用/弱引用的清理时机问题
    Java 8里,软引用默认是在老年代内存不足到一定程度才会被清理。如果首次Full GC时,JVM判断老年代还有“勉强够用”的空间,就不会去清理这些软引用指向的对象。但第一次GC后,内存很快又吃紧,触发第二次Full GC时,JVM才会强制清理软/弱引用,这时候就能回收大量垃圾。而Tomcat的SSL组件(比如会话缓存、密钥库相关对象)很可能用了这类引用存临时数据。

  2. Tomcat SSL会话缓存配置不合理
    Tomcat的SSL Connector默认有会话缓存,如果sessionCacheSize设得太大,或者sessionTimeout太长,会导致大量SSLSession对象堆积在老年代。首次Full GC时,这些会话还没到过期时间,JVM判定为存活对象;但第一次GC后,部分会话到期失效,第二次GC就把它们回收了。

  3. Java 8 Parallel GC的Ergonomics策略缺陷
    你日志里的Full GC (Ergonomics)说明是JVM自适应调优触发的GC。早期Java 8的Parallel GC(也就是你用的PSYoungGen+PSOldGen组合)的Ergonomics策略存在小问题:首次触发的Full GC可能只是做了轻量级检查,没有完整扫描所有可回收对象,第二次GC才会进入全量回收流程。

排查与解决步骤

按优先级来,一步步试:

  • 第一步:补全GC日志,精准定位
    给JVM加这些参数,把GC细节打出来:
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintReferenceGC"

重点看PrintReferenceGC的输出,确认是不是软/弱引用没在首次GC里被回收;同时对比两次GC前后老年代的对象类型变化。

  • 第二步:调整Tomcat SSL会话缓存配置
    打开server.xml找到SSL Connector,调整这两个参数:
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           clientAuth="false" sslProtocol="TLS"
           sessionTimeout="600"  <!-- 把会话超时改成10分钟(单位秒) -->
           sessionCacheSize="1000" />  <!-- 限制缓存的会话数 -->

缩小缓存规模+缩短超时时间,减少老年代里的会话对象堆积。

  • 第三步:强制Full GC时清理软引用
    添加JVM参数,让JVM在Full GC时直接清理所有软引用,不用等内存阈值:
JAVA_OPTS="$JAVA_OPTS -XX:SoftRefLRUPolicyMSPerMB=0"

这样首次Full GC就能把软引用指向的垃圾都清掉,避免第二次GC快速触发。

  • 第四步:升级Java 8补丁版本
    如果是早期Java 8(比如u100之前的版本),Parallel GC的Ergonomics确实有一些小bug,升级到最新的Java 8补丁版本(比如u392),很多这类问题都被修复了。

  • 第五步:堆转储分析根源
    如果上面的方法都没解决,导出堆转储文件分析:

jmap -dump:format=b,file=heapdump.hprof <你的Tomcat进程ID>

用MAT(Memory Analyzer Tool)打开堆转储,看老年代里占比最高的对象类型,是不是SSL相关的对象(比如javax.net.ssl.SSLSession),找到具体的内存泄漏点。

总结

这种“首次GC无效、第二次GC猛回收”的情况,90%以上和引用清理时机或者缓存过期策略有关,结合你的SSL环境,优先从会话缓存和软引用配置入手,再通过GC日志和堆转储定位问题,应该能快速解决。

内容的提问来源于stack exchange,提问作者Ankur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:37:20