0
点赞
收藏
分享

微信扫一扫

几种Java溢出

张宏涛心理 2022-02-25 阅读 48


一、堆溢出

所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节。

public class HeapOOM { 

static class OOMObject{}

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

while(true){
list.add(new OOMObject());
}
}
}

加上JVM参数-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快报出OOM

​Exception in thread "main" java.lang.OutOfMemoryError: Java heap space​

并且能自动生成Dump。

二、方法区溢出

方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带

public class MethodAreaOOM { 

static class OOMOjbect{}

public static void main(String[] args) {
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();
}
}

}

加上永久带的JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:

​Exception in thread "main" java.lang.OutOfMemoryError: PermGen space​

静态变量或常量也会有可能撑爆方法区:

public class ConstantOOM { 

public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
}
}

}

同样加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后报如下异常:

​Exception in thread "main" java.lang.OutOfMemoryError: PermGen space​

三、Java栈和本地方法栈

栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,栈大小由Xss来调节,方法调用层次太多会撑爆这个区域,如下所示:

public class StackOOM { 

private int stackLength = 1;

public void stackLeak(){
stackLength++;
stackLeak();
}

public static void main(String[] args) throws Throwable{
StackOOM oom = new StackOOM();
try{
oom.stackLeak();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}

设置JVM参数:-Xss128k,报出异常:

​Exception in thread "main" java.lang.StackOverflowError​

打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:

public class StackOOM { 

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() {
dontStop();
}
});
t.start();
stackLength++;
}
}

public static void main(String[] args) throws Throwable{
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​

不过在windows上运行这个例子要小心,会出现系统假死的情况,有可能需要重启机器才行。

其他资料:​​JVM原理讲解和调优​​

(END)



举报

相关推荐

0 条评论