tomcat9 java.lang.OutOfMemoryError: Java heap space的解决方法

1、报错的原因

tomcat设置的内存分配有问题,导致没有足够的内存来处理,所以就会报上面的错误。

2、详细说明

在 Tomcat 9 中出现 java.lang.OutOfMemoryError: Java heap space 错误,意味着 Java 虚拟机 (JVM) 的堆内存不足以处理应用程序的运行需求。

1). 增加 JVM 堆内存大小

通过调整 JAVA_OPTS 环境变量增加堆内存上限(-Xmx)和初始堆大小(-Xms)。

步骤:

  1. 找到 Tomcat 的 bin/setenv.sh(Linux/Mac)或 bin/setenv.bat(Windows)文件,没有则创建。
  2. 添加以下配置(示例为分配 2GB 堆内存):

bash

# Linux/Mac (setenv.sh)
JAVA_OPTS="-Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"

batch

# Windows (setenv.bat)
set JAVA_OPTS=-Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m

参数说明:

  • -Xms1024m:初始堆大小 1GB。
  • -Xmx2048m:最大堆大小 2GB。
  • -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize:非堆内存(类元数据)大小限制。

只要调整-Xmx2048m:最大堆大小 2GB。这个值,就可以解决问题。

2). 优化应用程序内存使用

检查代码中是否存在内存泄漏或过度消耗内存的逻辑:

  • 对象未释放:确保 try-with-resources 或 finally 块中关闭资源(如数据库连接、文件流)。
  • 静态集合:避免静态集合持有大量对象引用。
  • 缓存过大:控制缓存大小(如 Ehcache、Guava Cache 的 maximumSize)。
  • 大对象处理:分批处理大数据集,避免一次性加载全部数据到内存。

3). 启用垃圾回收日志分析

添加 GC 日志参数,分析内存使用模式:

bash

JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:$CATALINA_BASE/logs/gc.log"

通过工具(如 GCEasy)分析日志,确定是否存在频繁 Full GC 或内存泄漏。

4). 使用内存分析工具

生成堆转储文件(Heap Dump)并分析:

bash

JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_BASE/logs/heapdump.hprof"

使用工具(如 VisualVM、Eclipse Memory Analyzer)打开转储文件,查找大对象或内存泄漏点。

3、实际操作

只要在Java Options这栏里,加入设置就可以顺利解决。之前的设置是-Xmx512m,然后上传大图片的时候,就会报错,修改完成以后,就可以上传成功了。

4、-XX:MetaspaceSize 和 -XX:PermSize

在 Java 虚拟机 (JVM) 中,-XX:MetaspaceSize 和 -XX:PermSize 分别对应不同版本的方法区实现,但两者存在显著差异。以下是详细解释:

1. 方法区的历史演变

  • JDK 7 及以前:方法区由 永久代(PermGen) 实现,使用堆内存的一部分,通过 -XX:PermSize 和 -XX:MaxPermSize 控制大小。
  • JDK 8 及以后:永久代被 元空间(Metaspace) 取代,使用本地内存(非堆),通过 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 控制大小。

2. 永久代(PermGen)与元空间(Metaspace)的区别

特性永久代(PermGen)元空间(Metaspace)
内存位置堆内存的一部分本地内存(非堆)
大小限制必须通过 -XX:MaxPermSize 显式设置上限默认无上限(受系统物理内存限制)
溢出错误java.lang.OutOfMemoryError: PermGen spacejava.lang.OutOfMemoryError: Metaspace
自动回收回收效率低,易导致 Full GC更高效的垃圾回收,减少 Full GC
存储内容类元数据、静态变量、字符串常量池等类元数据(字符串常量池移至堆内存)

3. 参数详解

永久代参数(JDK 7 及以前)
  • -XX:PermSize:永久代初始大小(默认约 20.75MB)。
  • -XX:MaxPermSize:永久代最大大小(默认约 82MB)。

示例:

bash

java -XX:PermSize=128m -XX:MaxPermSize=256m YourMainClass
元空间参数(JDK 8 及以后)
  • -XX:MetaspaceSize:触发元空间垃圾回收的初始阈值(默认约 21MB)。
  • -XX:MaxMetaspaceSize:元空间最大大小(默认无上限,需手动设置)。
  • -XX:MinMetaspaceFreeRatio:GC 后最小空闲比例(默认 40%)。
  • -XX:MaxMetaspaceFreeRatio:GC 后最大空闲比例(默认 70%)。

示例:

bash

java -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m YourMainClass

4. 为什么替换永久代?

  • 内存管理更灵活:元空间使用本地内存,避免永久代的固定大小限制,减少 PermGen space 溢出。
  • GC 效率提升:元空间的垃圾回收更高效,减少 Full GC 频率。
  • 简化调优:无需手动设置 -XX:MaxPermSize,降低 OOM 风险。

5. 典型场景与调优建议

场景 1:类加载过多(如 Tomcat、Spring 应用)
  • 永久代:易触发 PermGen space 溢出,需增大 -XX:MaxPermSize
  • 元空间:需设置合理的 -XX:MaxMetaspaceSize,避免无限增长导致系统内存耗尽。
场景 2:频繁部署应用(如 DevOps 环境)
  • 永久代:类卸载困难,Full GC 频繁。
  • 元空间:类卸载更彻底,GC 效率更高。

6. 如何判断是否需要调整?

  • 永久代溢出:日志中出现 java.lang.OutOfMemoryError: PermGen space
  • 元空间溢出:日志中出现 java.lang.OutOfMemoryError: Metaspace
  • GC 日志分析:观察 Full GC 频率和元空间使用趋势。

总结

  • JDK 7 及以前:使用 -XX:PermSize 和 -XX:MaxPermSize 控制永久代大小。
  • JDK 8 及以后:使用 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 控制元空间大小,推荐设置合理的 MaxMetaspaceSize 以避免内存耗尽。

升级到 JDK 8+ 后,建议优先使用元空间,并根据应用特性调整参数。

5、总结

只要按照实际操作说明就可以解决,有兴趣的小伙伴,可以自己亲自测试下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值