温馨提示×

Tomcat在Linux上如何解决内存溢出

小樊
31
2025-12-16 21:01:40
栏目: 智能运维

Linux下Tomcat内存溢出定位与解决

一、快速判断错误类型

  • 查看 Tomcat 日志tail -f **$CATALINA_HOME/logs/catalina.out**,根据异常关键字定位类型。常见三类:
    • Java heap space:堆内存不足,对象申请超出 -Xmx 上限。
    • PermGen space / Metaspace:类与元数据区不足(Java 8 之前为 PermGen,Java 8+ 为 Metaspace)。
    • unable to create new native thread:系统无法再创建本地线程,多与系统/容器资源限制或栈占用有关。

二、对应场景与解决方案

  • 堆内存不足(Java heap space)

    • 现象:日志出现 OutOfMemoryError: Java heap space;应用吞吐下降、Full GC 频繁。
    • 处置:
      • 适度提升堆上限:设置 -Xms-Xmx(建议等值,如 -Xms2g -Xmx2g),并控制堆占物理内存不超过约 80%
      • 调整新生代:用 -Xmn 设置新生代大小,常取 -Xmx 的 1/4 作为起点,结合 GC 日志再微调。
      • 打开 GC 日志,观察回收效果与停顿:如 -verbose:gc -Xloggc:gc.log,必要时选择更合适的垃圾回收器。
  • 元空间不足(Metaspace / PermGen)

    • 现象:Java 7/更早出现 PermGen space;Java 8+ 出现 Metaspace
    • 处置:
      • Java 8+:设置 -XX:MaxMetaspaceSize=…(如 512m/1g),避免无限制增长。
      • Java 7 及更早:设置 -XX:PermSize=… -XX:MaxPermSize=…
      • 减少类加载冗余:清理重复的 第三方 JAR,或将共用 JAR 放入 tomcat/shared/lib(视版本与打包方式而定)。
  • 无法创建新线程(unable to create new native thread)

    • 现象:日志报无法创建新线程,或系统监控显示线程数触顶。
    • 处置:
      • 检查系统/容器限制:ulimit -u(用户进程数)、ulimit -n(文件句柄数)、ulimit -s(栈大小)。
      • 降低单线程栈占用:适度减小 -Xss(如 512k–1m 区间尝试),以换取可创建的线程数空间。
      • 估算上限:最大线程数 ≈ (MaxProcessMemory − JVMMemory − ReservedOsMemory) / ThreadStackSize;必要时减少 -Xmx 为线程栈留出更多空间。
  • 系统层 OOM 导致进程被杀(非 JVM 异常)

    • 现象:应用突断、SSH 不上;检查 /var/log/messagesdmesg 可见 oom-killer 记录,且 free 显示 Swap: 0
    • 处置:
      • 增加 Swap 空间或降低业务峰值内存占用;压测时避免一次性把物理内存打满。
      • 合理设置 -Xmx,避免多个实例/进程叠加占用超出物理内存。

三、Linux 下 Tomcat 配置与生效步骤

  • 修改 $CATALINA_HOME/bin/catalina.sh,在文件靠前位置(如注释块之后、cygwin=false 之前)加入 JAVA_OPTS,例如:
    • Java 8+ 常用示例:
      JAVA_OPTS="-server -Xms2g -Xmx2g -Xmn512m \
        -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \
        -Xss512k -verbose:gc -Xloggc:gc.log"
      
    • Java 7 及更早(使用 PermGen):
      JAVA_OPTS="-server -Xms2g -Xmx2g -Xmn512m \
        -XX:PermSize=256m -XX:MaxPermSize=512m \
        -Xss512k -verbose:gc -Xloggc:gc.log"
      
    • 注意:
      • -Xms-Xmx 设为等值可减少堆动态扩缩带来的抖动。
      • 32 位 JVM 进程空间受限,生产建议使用 64 位 JDK 与足够物理内存。

四、验证与长期优化建议

  • 验证配置是否生效:
    • 重启后在 catalina.outps -ef | grep java 中确认参数已传入;用 jstat -gc <pid>jmap -heap <pid> 观察堆与元空间使用。
  • 建立监控与基线:
    • 持续收集 GC 日志、线程数、堆/元空间、文件句柄等指标;压测或峰值期重点观察 Full GC 与 OOM 风险点。
  • 代码与架构层面优化:
    • 控制对象生命周期与缓存大小,避免内存泄漏;减少类加载器泄漏(热部署频繁的场景尤需关注)。
    • 限流与异步化,降低瞬时并发与线程峰值;必要时拆分服务、隔离大对象处理。

0