Java虚拟机运行时数据区

原创
2014/08/09 14:15
阅读数 995
 java虚拟机运行时数据区总结了一张图片,方便记忆:

OutOfMemoryError异常:

1.java堆溢出
测试:java堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免自动扩展,然后不停的创建对象。
结果:java.lang.OutOfMemoryError:Java heap space...

2.运行时常量池溢出
测试:通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制了常量池的容量,然后通过String类的intern()方法来填充常量池。
结果:java.lang.OutOfMemoryError:PermGen space

3.方法区溢出
测试:同上通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,然后借助CGLib直接操作字节码运行时,生成大量的动态类。
结果:java.lang.OutOfMemoryError:PermGen space

4.虚拟机栈和本地方法栈溢出
测试:栈容量是由-Xss参数设定
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError
如果虚拟机在扩展栈时无法申请到足够的内存空间则抛出OutOfMemoryError

/**
 * VM Args:-Xss128k
 * 
 * @author ksfzhaohui
 * 
 */
public class JavaVMStackSOF {
	private static Log logger = LogFactory.getLog(JavaVMStackSOF.class);
	private int stackLength = 1;

	public void stackLeak() {
		stackLength++;
		stackLeak();
	}
	public static void main(String[] args) {
		JavaVMStackSOF oom = new JavaVMStackSOF();
		try {
			oom.stackLeak();
		} catch (Throwable e) {
			logger.info("stack length:" + oom.stackLength);
			logger.error(e);
		}
	}
}

在单个线程下,无论是由于栈帧太大,还是虚拟机栈容量太小,当内存无法分配是,虚拟机都抛出StackOverflowError。
如果测试不限于单线程,通过不断的建立线程的方式倒是可以产生OutOfMemoryError

/**
 * VM Args:-Xss2M
 * 
 * @author ksfzhaohui
 * 
 */
public class JavaVMStackOOM {

	private void dontStop() {
		while (true) {

		}
	}
	public void stackLeakByThread() {
		while (true) {
			Thread thread = new Thread(new Runnable() {

				@Override
				public void run() {
					dontStop();
				}
			});
			thread.start();
		}
	}

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


5.本机直接内存溢出

测试:通过-XX:MaxDirectMemorySize直接内存,通过ByteBuffer.allocateDirect方法分配内存,查看DirectByteBuffer类,其实内部真正分配内存的是UnSafe类 

/**
 * -Xmx20m -Xms20m -XX:MaxDirectMemorySize=10m
 * 
 * @author ksfzhaohui
 * 
 */
public class DirectMemoryOOM {

	private static final int _1MB = 1024 * 1024;

	public static void main(String[] args) throws IllegalArgumentException,
			IllegalAccessException {
		Field unsafeField = Unsafe.class.getDeclaredFields()[0];
		unsafeField.setAccessible(true);
		Unsafe unsafe = (Unsafe) unsafeField.get(null);
		while (true) {
			unsafe.allocateMemory(_1MB);
		}
	}
}
结果: java.lang.OutOfMemoryError

参考:深入java虚拟机

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
10 收藏
0
分享
返回顶部
顶部