好的,阿杰,我们来系统讲解 Java 中 java.lang.OutOfMemoryError: Java heap space 的解决方法,以及常用的 JVM 参数设置。我会分步骤详细说明。


1️⃣ 问题概述

错误信息:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

  • 含义:JVM 堆内存不足,无法分配对象。
  • 常见场景
    1. 对象创建过多(如大集合、缓存、数组)。
    2. 内存泄漏(对象无法被 GC 回收)。
    3. 堆内存设置过小,无法满足程序需求。

2️⃣ JVM 堆内存结构

  • Heap(堆):存放 Java 对象实例。
  • Metaspace / PermGen:存放类信息(Java 8 及以上使用 Metaspace)。
  • 堆内存分区:
    • Young Generation(Eden + Survivor)
    • Old Generation(Tenured)
  • Java heap space 指堆整体空间不足。

3️⃣ 解决方法

方法一:增大 JVM 堆内存

使用 JVM 参数:

-Xms512m    # 初始堆大小
-Xmx2g      # 最大堆大小
-XX:NewSize=256m   # 年轻代初始大小
-XX:MaxNewSize=1g  # 年轻代最大大小

示例:

java -Xms512m -Xmx2g -jar myapp.jar

  • 建议
    • -Xms 设置与 -Xmx 相同可以减少堆扩展带来的性能消耗。
    • 根据程序需求调整,一般应用服务器 1-4G 堆内存较常见。

方法二:分析对象和内存使用

  1. 使用工具查看堆使用情况
    • jconsole / jvisualvm(JDK 自带 GUI)
    • jmap + jhat(命令行)
    • Eclipse Memory Analyzer (MAT)
  2. 排查大对象 / 内存泄漏
    • 过大的集合,如 List<String> 放入百万条数据
    • 缓存未清理
    • 静态对象长期占用

方法三:优化代码

  • 减少不必要的对象创建
  • 尽量用基本类型或对象复用
  • 对集合使用合理的初始容量,避免频繁扩容
  • 关闭或清理不再使用的资源(如 InputStreamResultSet

方法四:使用堆外内存(适合高性能缓存)

  • 使用 DirectByteBuffer 或 off-heap 技术
  • JVM 参数示例:
-XX:MaxDirectMemorySize=1g

适合 Netty、缓存类应用


方法五:调整 GC 策略(可选)

  • 默认 GC:并行收集器(Parallel GC)
  • 可以尝试 G1 GC 进行大堆优化:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200


4️⃣ 常用 JVM 堆内存参数总结

参数含义示例
-Xms堆初始大小-Xms512m
-Xmx堆最大大小-Xmx2g
-XX:NewSize年轻代初始大小-XX:NewSize=256m
-XX:MaxNewSize年轻代最大大小-XX:MaxNewSize=1g
-XX:+UseG1GC使用 G1 GC
-XX:MaxPermSizePermGen 大小(Java 7 及以下)-XX:MaxPermSize=256m
-XX:MaxMetaspaceSizeMetaspace 最大大小(Java 8+)-XX:MaxMetaspaceSize=256m

✅ 小结

  1. 快速解决 → 增大 -Xmx
  2. 长期优化 → 分析内存使用,优化代码。
  3. 适用场景
    • 开发阶段:小堆 + 内存分析
    • 生产环境:合适堆大小 + GC 调优 + 内存监控