java虚拟机java.lang.OutOfMemoryError系列之Java heap space解决思路

工作中虽然不经常遇到java.lang.OutOfMemoryError: Java heap space,但一旦出现将会严重影响系统运行,如果不能迅速解决,将会带来很恶劣的影响,所以掌握OutOfMemoryError:Java heap space的解决方法也是非常有必要的。

解决问题首先要找出原因,要找原因要有依据,而内存溢出时的堆dump信息是最为重要的依据之一

步骤一:先保证能拿到堆dump信息

我写了一个简单的小例子,jvm运行参数为:-Xmx20M -Xms20M -XX:+HeapDumpOnOutOfMemoryError

public class HeapOutOfMemoryTest {
	public static void main(String args[]) throws InterruptedException {
		List<HeapOutOfMemoryTest> list = new ArrayList<HeapOutOfMemoryTest>();
		Thread.sleep(10000);
		for(int i=0;i <3; i++) {
			Thread.sleep(10);
			new Thread(new MyThread(), "Thread-" + i).start();
		}
	}
}
class MyThread implements Runnable{

	@Override
	public void run() {
		List<byte[]> list = new ArrayList<byte[]>();
		while(true) {
			byte[] b = new byte[100 * 1024];
			list.add(b);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

程序执行后很快就会抛出内存溢出错误

Exception in thread "Thread-0" Exception in thread "Thread-2" java.lang.OutOfMemoryError: Java heap space
	at li.cheng.jvm.chapter3.MyThread.run(HeapOutOfMemoryTest.java:23)
	at java.lang.Thread.run(Unknown Source)
java.lang.OutOfMemoryError: Java heap space
	at li.cheng.jvm.chapter3.MyThread.run(HeapOutOfMemoryTest.java:23)
	at java.lang.Thread.run(Unknown Source)

其实通过异常信息基本已经可以锁定内存溢出原因,但为了解决问题思路具有通用性,我们继续往下看

步骤二:分析堆内存溢出时的dump文件

堆dump文件可以直接下载我的dump文件,用Eclipse Memory Analyzer或者VisualVM打开,我用的是Eclipse Memory Analyzer

可以看到这两个线程占的内存总量达到了近90%

再进一步展开Thread-2的堆信息

可以看到有大量的byte数组,就是我们代码中新建的数组,正是因为这个原因导致内存溢出。当然在实际业务代码中能看到具体的业务类名称,基本上就一目了然了。

步骤三:如果堆dump信息也正常怎么办?

可能经过上面两个步骤的分析,虽然确实由于堆中对象太多导致内存溢出,但都是正常的对象,没有某个类的对象产生特别多的情况,应该怎么办?

这时候就考虑增大堆内存的大小,或者减少对象的产生

方法1:直接增加堆内存大小,调整-Xmx -Xms 的大小

方法2:本地缓存改为集中缓存。大量使用本地缓存(如大量使用HashMap作为K/V缓存),会占用堆上很多内存,尤其在集群情况下,会造成更多浪费,这时可以考虑把本地缓存改为集中缓存(如Redis)。

方法3:考虑优化代码,看是否有优化的空间。

 

当你遇到 `java.lang.OutOfMemoryError: Java heap space` 这种错误时,它表示Java虚拟机(JVM)在运行过程中无法分配足够的内存来处理当前的任务。Java堆空间是JVM用于存储对象实例以及数组的主要区域,当程序中的内存消耗超过了这个区域的最大限制,就会抛出此异常。 这通常发生在以下几种情况: 1. **大量对象创建**:如果你正在创建大量的大对象,如大型数据结构、大数据量的数组,或者递归深度过深,都可能导致堆空间不足。 2. **内存泄漏**:如果程序中存在未释放的资源,即使它们不再使用,也会持续占用内存,最终耗尽堆空间。 3. **设置不当的堆大小**:如果你在启动应用时指定了较小的堆大小 `-Xms` 和 `-Xmx` 参数,并且程序的需求超过了这个范围。 4. **长时间运行且不断增长的内存需求**:例如,数据库连接池中的长生命周期连接积累过多。 要解决这个问题,你可以尝试以下几个步骤: - **增加堆大小**:通过修改JVM启动选项,增大 `-Xms` 和 `-Xmx` 的值,给Java更多的内存空间。 - **优化内存使用**:检查代码是否有内存泄漏,及时关闭不需要的对象和资源。 - **调整对象大小和生命周期**:如果可能,考虑减少大对象的使用,或者优化对象的生命周期管理。 - **使用垃圾回收机制**:虽然Java有自动垃圾回收,但如果某些场景下回收不够及时,可以考虑使用并发或分代垃圾回收策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值