下面也来看一下上面说到的几个内存模块导致的内存溢出异常问题:
(这个也是面试的时候经常会被问到:比如叫你写一段让堆内存溢出的代码,或者是问你如果如果修改堆大小)
第一、堆溢出
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class HeapOOM {
static class OOMObject{}
/**
* @param args
*/
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}
我们上面看到堆主要是存放对象的,所以我们如果想让堆出现OOM的话,可以开一个死循环,然后产生新的对象就可以了。然后在将堆的大小调小点。
加上JVM参数
-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,
就能很快报出OOM:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
第二、栈溢出
[java] view plaincopy在CODE上查看代码片派生到我的代码片
package com.cutesource;
public class StackOOM {
/**
* @param args
*/
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
StackOOM oom = new StackOOM();
try{
oom.stackLeak();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}
我们知道栈中存放的方法执行的过程中需要的空间,所以我们可以下一个循环递归,这样方法栈就会出现OOM的异常了。
设置JVM参数:-Xss128k,报出异常:
Exception in thread "main" java.lang.StackOverflowError
打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
package com.cutesource;
public class StackOOM {
/**
* @param args
*/
private int stackLength = 1;
private void dontStop(){
while(true){
try{Thread.sleep(1000);}catch(Exception err){}
}
}
public void stackLeakByThread(){
while(true){
Thread t = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
dontStop();
}
});
t.start();
stackLength++;
}
}
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
StackOOM oom = new StackOOM();
try{
oom.stackLeakByThread();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}
这个栈的溢出,就是我们上面说到栈的时候的两种异常情况。
报出异常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread
第三、方法区溢出
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class MethodAreaOOM {
static class OOMOjbect{}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
while(true){
Enhancer eh = new Enhancer();
eh.setSuperclass(OOMOjbect.class);
eh.setUseCache(false);
eh.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object arg0, Method arg1,
Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
return arg3.invokeSuper(arg0, arg2);
}
});
eh.create();
}
}
}
我们知道方法区是存放一些类的信息等,所以我们可以使用类加载无限循环加载class,这样就会出现方法区的OOM异常。
手动将栈的大小调小点
加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
第四、常量池溢出
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class ConstantOOM {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}
我们知道常量池中存放的是运行过程中的常量,同时我们知道String类型的intern方法是将字符串的值放到常量池中的。所以上面弄可以开一个死循环将字符串的值都放到常量池中,这样常量池就会出现OOM异常了。因为常量池本身就是方法区的一部分,所以我们也可以手动的调节一下栈的大小。
没有评论