JVM—内存溢出、OutOfMemoryError、StackOverflowError
学习jvm时看到几篇非常好的系列文章,转载了:
一、概要
我们可以带着以下几个问题去学习自动内存管理机制,罗列如下:
- 什么操作可能导致内存溢出?
- 有哪些种类的内存溢出?
- 都是在内存的哪些区域溢出?
- 字节码解释器工作时通过改变它的值来选取下一条需要执行的字节码指令
- 分支、循环、跳转、异常处理和线程恢复都依赖于它
栈的作用:栈用于存储局部变量表、操作数栈、动态链接和方法出口等信息.
其中局部变量表用于存放8种基本数据类型(boolean,byte,char,short,int,float,long,double)和reference类型.
reference类型:
-
指向对象起始地址的引用指针
-
指向一个代表对象的句柄
-
指向一条字节码指令的地址
可抛出两种异常状况
-
线程请求的栈深度大于虚拟机所允许的栈深度,抛出StackOverflowError异常
-
当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常是
与虚拟机栈的作用非常相似.其区别是虚拟机栈执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务
同时也会抛出StackOverflowError和OutOfMemoryError异常
堆的作用:分配所有的对象实例和数组。可以抛出OutOfMemoryError异常。
方法区的作用:用于存储已被虚拟机加载的类信息(Class)、常量(final修饰)、静态变量(static)和即时编译器编译后的代码(code)
可以抛出OutOfMemoryError异常
属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用(在以后介绍Class结构会讲到),在类加载后存放到方法区的运行时常量池中。可抛出OutOfMemoryError异常
三、对象访问
主流的两种访问方式:使用句柄和直接指针。(HotSpot虚拟机就是使用直接指针的访问方式)
使用句柄访问
四、OutOfMemoryError异常
在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能.
下面通过若干实例来验证异常发生的场景.以下代码的开头都注释了执行时所需要设置的虚拟机启动参数,这些参数对实验结果有直接影响,请调试代码的时候不要忽略掉.
堆里放的是new出来的对象,所以这部分很简单不断的new对象就可以了,但是为了防止对象new出来之后被GC,所以把对象new出来的对象放到一个List中去即可。为了有更好的效果,可以在运行前,调整堆的参数。
-
import java.util.ArrayList;
-
import java.util.List;
-
/**
-
* VM Args: -Xms20m -Xms20m - XX:+HeapDumpOnOutOfMemoryError
-
* @author Administrator
-
*
-
*/
-
public class HeapOOM {
-
static class OOMObject{}
-
public static void main(String[] args) {
-
List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>();
-
while(true ){
-
list.add( new OOMObject());
-
}
-
}
-
}
- 在单线程的堆中我们不断的让一个成员变量自增,容纳这个变量的单元无法承受这个变量了,就抛出StackOverflowError了。
- 可以开尽量多的线程,并在每个线程里调用native的方法,就自然会抛出 OutOfMemoryError了。
-
/**
-
* VM Args: - Xss64k
-
* @author Administrator
-
*
-
*/
-
public class JavaVMStackSOF {
-
private int stackLength = 1;
-
public void stackLeak(){
-
stackLength ++;
-
stackLeak();
-
}
-
public static void main(String[] args) throws Throwable {
-
JavaVMStackSOF oom = new JavaVMStackSOF();
-
try{
-
oom.stackLeak();
-
} catch(Throwable e){
-
System. out.println("Stack length:" + oom.stackLength);
-
throw e;
-
}
-
}
-
}
-
import java.lang.reflect.Method;
-
import net.sf.cglib.proxy.MethodInterceptor;
-
import net.sf.cglib.proxy.Enhancer;
-
import net.sf.cglib.proxy.MethodProxy;
-
/**
-
* VM Args:- XX:PermSize=10m -XX:MaxPermSize=10m
-
* @author Administrator
-
*
-
*/
-
public class JavaMethodAreaOOM {
-
public static void main(String[] args) {
-
while (true ){
-
Enhancer enhancer = new Enhancer();
-
enhancer.setSuperclass(OOMObject. class );
-
enhancer.setUseCache( false );
-
enhancer.setCallback( new MethodInterceptor() {
-
-
public Object intercept(Object obj, Method method, Object[] args,
-
MethodProxy proxy) throws Throwable {
-
return proxy.invoke(obj, args);
-
}
-
});
-
enhancer.create();
-
}
-
}
-
static class OOMObject{
-
-
}
-
}
-
import java.util.ArrayList;
-
import java.util.List;
-
/**
-
* VM Args:- XX:PermSize=10m -XX:MaxPermSize=10m
-
* @author Administrator
-
*
-
*/
-
public class RuntimeConstantPoolOOM {
-
public static void main(String[] args) {
-
List<String> list = new ArrayList<String>();
-
int i = 0;
-
while (true ){
-
list.add(String. valueOf(i++).intern());
-
}
-
}
-
}
相关引用: