二、JVM(HotSpot)内存泄漏和内存溢出

注:本博文主要是基于JDK1.7会适当加入1.8内容。

1、Java堆溢出

//-Xms20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError
public class HeapOOM {
	static class OOMObject {}

	public static void main(String[] args) {
		List<OOMObject> list = new ArrayList<>();
	
		while(true) {
			list.add(new OOMObject());
		}
	}

}

运行上述代码,出现内存溢出错误即OutOfMemoryError,错误信息为参数-XX:HeapDumpOnOutOfMemoryError导出一份java_podxxxx.hprof的文件。分析dump文件,打开visualVM导入查看。(JDK中包含jvisualVM工具可进行查看)

题外话:出现OutOfMemoryError除了有内存溢出的可能性之外还存在内存泄漏的可能性。如果是内存溢出,则需要查看泄漏对象的GC Root的引用链。如果不是内存泄漏则可能是内存溢出,首先尝试调大-Xms和-Xmx,如果还是报错需要定位代码的问题(dump文件分析)

2、虚拟机栈和本地方法栈溢出

由于HotSpot虚拟机中不区分虚拟机栈和本地方法栈,一致通过-Xss调整栈内存大小。
如果线程请求的栈深度大于虚拟机所允许的最大深度则抛出StackOverflowError;如果虚拟机扩展栈内存无法申请到足够的内存空间时则抛出OutOfMemoryError。

//-Xss128k
public  class JavaVMStackSOF {

	private int stackLength = 1;
	
	public void stackLeak() {
		stackLength++;
		stackLeak();
	}

	public static void main(String[] args) {
		JavaVMStackSOF sof = new JavaVMStackSOF();
		
		try{
			sof.stackLeak();
		} catch(Throwable e) {
			throw e;
		}
	}
	
}

运行上述代码,出现内存溢出错误即OutOfMemoryError。在单线程下,无论栈帧太大还是虚拟机栈容量太小,当内存无法分配的时候虚拟机抛出的都是OutOfMemoryError。然而,在多线程情况下,是可以出现StackOverflowError,虚拟机为每个进程提供内存都是有限制的,栈内存大小约等于物理内存减去最大堆内存和方法区容量(JDK1.8已经替换为Metaspace),每个线程分配到的栈容量越大则可建立的线程数越少,建立线程就可以将剩余的内存耗尽。

//-Xss2m
public class JavaVMStackOOM {

	private void doNotStop() {
		while(true) {}

		private void stackLeakByThread() {
			while(true) {
				Thread thread = new Thread(()-> doNotStop());
				thread.start();
			}
		}

		public static void main(String[] args) {
			JavaVMStackOOM oom = new JavaVMStackOOM();
			oom.stackLeakByThread();
		}
	}
}

注意:这段代码如果执行在Windows操作系统中,会导致系统假死现象,原因是Java的线程会映射到操作系统的内核线程上(需要重启机器)。

3、方法区和运行时常量池溢出(运行时常量池JDK1.7移除方法区,JDK1.8已经移除方法区设置Metaspace)

请参考上一章String.intern代码解释。

4、直接内存溢出

直接内存容量可以通过参数-XX:MaxDirectMemorySize指定,若不指定则默认与Java堆最大值(-Xmx)一样。直接内存溢出明显特征是Heap Dump文件中不会看见明显的异常排除堆内存溢出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值