1、报错的原因
tomcat设置的内存分配有问题,导致没有足够的内存来处理,所以就会报上面的错误。
2、详细说明
在 Tomcat 9 中出现 java.lang.OutOfMemoryError: Java heap space 错误,意味着 Java 虚拟机 (JVM) 的堆内存不足以处理应用程序的运行需求。
1). 增加 JVM 堆内存大小
通过调整 JAVA_OPTS 环境变量增加堆内存上限(-Xmx)和初始堆大小(-Xms)。
步骤:
- 找到 Tomcat 的
bin/setenv.sh(Linux/Mac)或bin/setenv.bat(Windows)文件,没有则创建。 - 添加以下配置(示例为分配 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 space | java.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、总结
只要按照实际操作说明就可以解决,有兴趣的小伙伴,可以自己亲自测试下。

2286

被折叠的 条评论
为什么被折叠?



