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

本文介绍了Java程序中出现内存溢出错误的原因及解决方法,包括如何调整JVM堆大小、减少应用程序内存消耗以及处理对象引用保留问题。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space解决方法

问题描述
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

解决方案[转]
一直都知道可以设置jvm heap大小,一直用eclipse写/调试java程序。一直用命令行or console加参数跑程序。现象:在eclipse的配置文件eclipse.ini中设置-vmargs -Xms500m -Xmx1024m,在eclipse中直接run 或者debug某些耗内存的程序时依然出现java.lang.OutOfMemoryError: Java Heap Space错误,即通常认为的内存不足,java虚拟机内存不够用。而在命令行加这些参数则有效果,不会出错。这说明一个问题,这些参数根本没有起作用。今天需要在eclipse里调试程序,还没到需要调试的地方就heap error了,在网上搜了很多地方,得到了最终的答案:
选中被运行的类,点击菜单‘run->run...’,选择(x)=Argument标签页下的vm arguments框里
输入 -Xmx800m, 保存运行。
原来还需要对每个project单独设置,汗...


有三种可能导致OutOfMemoryError。首先是,此JVM有真实的内存泄漏,导致此JVM堆在内部实现时产生了一个Bug。这极不可靠。所有JVM都经过充分的测试,并且,如果有人发现这种bug,它将绝对是最高的优先级。因此你可以非常宽心地排除这种可能性。

第二种可能的OutOfMemoryError原因只不过是,你没有为你的应用程序运行时给予足够多的可用内存。这种情况,有两种可能的方案,或者增加 JVM堆可用大小,或者减少你的应用程序所需的内存总量。提高JVM可用堆大小可以简单的使用JVM的 -Xmx 参数。假如你将此参数设置尽可能的大(可用内存极限不要超过系统物理内存,否则你的应用程序将分页并暂停),仍然有以上所提到的内存问题,那么,你需要减 少你的应用程序所可能用到内存总量。减少应用程序内存可能是简单的,你可能允许一些集合过大,例如使用了许多大的缓冲区。或者它过于复杂,要求你重新实现 一些类,乃至重新设计应用程序。

读者 Jams Stauffer 指出有些JVM(例如 sun的 JVMs),还有一个“Perm”参数用来处理JVM结构与类对象。如果你正在使用一个数量非常巨大的类集,它有可能运行在"Perm"空间之外,然后你 需要增加此空间的大小,例如,sun的JVM使用 -XX:PermSize 与 -XX:MaxPermSize 选项。

第三种导致OutOfMemoryError最为常见,无心的对象引用保持。你没有明确无误的释放对象,以致于你的堆增长再增长,直到你没有额外的空间。

处理OutOfMemoryError:

是JVM内部的BUG?不太可能。如果是,这是优先级最高的BUG(为什么还没有人发现它,而你碰到了?)。

没有足够的内存分配给实际运行的应用程序?两种选择:使用-Xmx参数增加堆的最大使用内存(或者使用-XX:MaxPermSize参数增加Perm空 间大小); 或者使用更小的集合/缓冲区/表空间/对象.....,以减少所需要的内存总量,也就是说,可以调整对象大小,重新设计与重新实现你的应用程 序。

无心的对象引用保持?找到保持这些无意引用的源对象,改变它并释放这些对象。在IBM开发者社区的文章纲要式的揭示了这样一个通用的处理过程。这个过程主 要是等到应用程序到达恒定状态--你将期望最多的新创建的对象是临时对象,并且可以被垃圾收集器收集。这常常是在应用程序所有的初始化工作完成之后。

强迫垃圾收集,获得一个堆的对象快照。
做任何工作可能正在导到无意的对象引用保持。
强迫另一次垃圾收集并获得第二次堆的对象快照。
比较这两个快照,观察从第一个快照到第二个快照哪些对象在数量上有所增加。因为你在快照之前强迫垃圾收集,剩下的将是所有被应用程序引用的对象,比较两个快照将准确的标识那些新创建的、保留在应用程序里的对象。
根据你对应用程序的认识,决定两个快照比较中,哪些对象正在无意的保持对象引用。
跟踪前导引用,找到哪些对象正在引用这些无意的保持对象,直到你找到导致此问题的源对象

启动虚拟机的时候,加上一个参数:-Xms800m -Xmx800m就好了
-Xms <size>
设置JVM初始化堆内存大小

-Xmx <size>
设置JVM最大的堆内存大小

如果是应用程序,则:java -Xms800m -Xmx800m 你的类名
如果是tomcat之类的web服务器,在这个服务器的启动文件后面加上这个参数即可。


另外设置环境变量
JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "

### 问题分析 `java.lang.OutOfMemoryError: Java heap space` 是Java程序运行时常见的错误,表示Java虚拟机(JVM)的堆内存不足。堆内存用于存储对象实例,当程序创建的对象过多或过大,超出JVM堆内存限制时,就会触发该错误。此问题的解决方法通常涉及调整JVM的堆内存参数,优化程序代码,或通过工具分析内存使用情况。 ### 解决方案 #### 1. **增加JVM堆内存大小** 可以通过设置JVM启动参数来增加堆内存的大小。常用的参数包括: - `-Xms`:设置JVM堆内存的初始值。 - `-Xmx`:设置JVM堆内存的最大值。 例如,将JVM的初始堆内存设置为2GB,最大堆内存设置为4GB: ```bash java -Xms2g -Xmx4g -jar your-application.jar ``` 对于IDEA等开发工具,可以在启动配置中修改这些参数。在IntelliJ IDEA中,找到 `idea64.vmoptions` 文件(通常位于安装目录的 `bin` 文件夹下),并修改以下参数: ```properties -Xms512m -Xmx2048m ``` 对于Tomcat服务器,可以在 `catalina.bat`(Windows)或 `catalina.sh`(Linux)文件中添加以下内容: ```bat set JAVA_OPTS=%JAVA_OPTS% -Xms512m -Xmx2048m ``` #### 2. **优化程序代码** - **减少对象创建**:避免在循环或高频调用的方法中频繁创建对象。可以使用对象池或复用已有的对象。 - **及时释放内存**:确保不再使用的对象可以被垃圾回收。避免内存泄漏,例如未关闭的流、未释放的资源或持有大量数据的静态变量。 - **使用合适的数据结构**:选择内存占用较低的数据结构。例如,使用 `ArrayList` 代替 `LinkedList`,或者使用 `HashMap` 代替 `TreeMap`。 #### 3. **使用内存分析工具** 可以通过内存分析工具来诊断内存使用情况,找出内存瓶颈。常用的工具包括: - **VisualVM**:一个免费的可视化工具,支持监控JVM的内存使用情况、线程状态和垃圾回收。 - **MAT (Memory Analyzer)**:用于分析堆转储文件(Heap Dump),帮助识别内存泄漏和占用内存较多的对象。 生成堆转储文件的方法: ```bash jmap -dump:live,format=b,file=heapdump.hprof <pid> ``` 然后使用MAT工具打开堆转储文件进行分析。 #### 4. **调整垃圾回收器** 不同的垃圾回收器对内存管理的效率不同。可以根据程序的特性选择合适的垃圾回收器。常用的垃圾回收器包括: - **Serial GC**:适用于单线程环境。 - **Parallel GC**:适用于多线程环境,注重吞吐量。 - **CMS GC**:注重低延迟,适合需要快速响应的应用。 - **G1 GC**:兼顾吞吐量和低延迟,适用于大堆内存场景。 启用G1垃圾回收器的示例: ```bash java -XX:+UseG1GC -Xms2g -Xmx4g -jar your-application.jar ``` #### 5. **分页处理大数据** 如果程序需要处理大量数据,可以采用分页处理的方式,避免一次性加载所有数据到内存中。例如,数据库查询时可以使用分页查询: ```sql SELECT * FROM table_name LIMIT 1000 OFFSET 0; ``` 在代码中逐批处理数据,减少内存压力。 #### 6. **压缩数据存储** 对于需要存储大量数据的场景,可以采用压缩技术来减少内存占用。例如,使用 `GZIP` 或 `Snappy` 压缩数据,或者使用更高效的数据格式(如 `Parquet` 或 `Avro`)。 ### 示例代码 以下是一个简单的Java程序,演示如何调整堆内存并监控内存使用情况: ```java public class MemoryTest { public static void main(String[] args) { // 获取运行时环境 Runtime runtime = Runtime.getRuntime(); // 打印当前内存使用情况 System.out.println("Total Memory: " + runtime.totalMemory()); System.out.println("Free Memory: " + runtime.freeMemory()); // 创建大量对象 try { byte[][] data = new byte[1000][]; for (int i = 0; i < 1000; i++) { data[i] = new byte[1024 * 1024]; // 分配1MB内存 } } catch (OutOfMemoryError e) { System.err.println("Out of memory: " + e.getMessage()); } } } ``` ###
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值