前几天读《深入理解Java虚拟机》测试了一下书中所写的java虚拟机异常的代码,特在此整理一下。
Java堆溢出
众所周知,JVM(java虚拟机)中堆是用于存放对象实例的,想要令其发生溢出,只需要不断创造对象便可。
代码如下:
public class HeapOOM {
static class OOMObject {}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>();
int i = 0;
while (true) {
list.add(new OOMObject());
}
}
}
运行结果:
java.lang.OutOfMemoryError: Java heap space
栈溢出
java中栈分为两类:Java虚拟机栈和本地方法栈,java虚拟机栈为java虚拟机的方法提供服务,而本地方法栈则是为虚拟机使用的Native方法提供服务。二者的溢出方式均相同,都可分为两种:
- 线程请求深度大于虚拟机允许的最大深度,抛出StackOverflowError异常
虚拟机扩展栈时无法申请到足够的内存空间,就会抛出OutOfMemeoryError异常
栈深度溢出的代码如下:
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;
}
}
}
运行结果:
stack length:9506
* Exception in thread "main" java.lang.StackOverflowError
栈容量溢出:
此处书中代码有问题,本人未能成功测试(毕竟是国人写的书,质量不过关)。真正的测试代码日后另行附上。。。
运行时常量池溢出
java虚拟机中运行时常量池是java虚拟机中方法区的一部分,用于存放编译期生成的各类字面量和符号引用。
想要使运行时常量池溢出,需要用到String.intern()这个Native方法。该方法的作用是:如果池中包含此String对象的字符串,则返回池中这个字符串的String对象;否则将此对象所包含的字符串添加到常量池中,并返回此String对象的引用。
代码如下
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());
}
}
}
运行结果“
java.lang.OutOfMemoryError: PermGen space
方法区溢出
方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。这个测试基本方法是产生大量的类去填充方法区。
但由于这个测试书中借用了CGLib项目,本人手上无此项目,故未做测试,先将代码附上吧:
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 Throeable{
return proxy.invokeSuper(obj,args);
}
});
enchaner.create();
}
}
static class OOMObject {}
}
本机直接内存溢出
本机直接内存抛出异常的代码如下:
public class DirectMemoryOOM {
private static final int _1MB = 1024*1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}
运行结果为:
java.lang.OutOfMemoryError