内存溢出分析总结

来源:互联网 发布:女生半袖图片淘宝 编辑:程序博客网 时间:2024/05/21 21:35

堆溢出

堆中一般存放对象、数组等大对象,当堆中的对象达到堆的最大容量限制后,就会产生内存溢出
JVMargs:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError

public class HeapOOM { static class OOMObject{}public static void main(String[] args) throws InterruptedException {  List<OOMObject>list=new ArrayList<OOMObject>();  while(true) {  list.add(newOOMObject()); }}}


Jdk1.7中,常量池被移到了堆中,因此也会因为过多常量导致溢出

int i=0;while (true) {   list.add(String.valueOf(i++));//会导致堆溢出}

栈溢出

所有栈的总空间无法规定,所以栈的总空间≈机器内存-堆内存-方法区

1、StackOverflowError:线程请求的深度大于虚拟机所允许的最大深度

        单线程操作中,只能产生StackOverflowError异常
        使用-Xss参数减少单个栈内存的容量,结果抛出StackOverflowError异常,且异常输出时堆栈深度相应缩小
        再增大本地变量占用空间(增大栈帧中本地变量表的长度),结果抛出StackOverflowError异常时,堆栈深度再次缩小

public class StackSOF {private int stacklength=1;//模拟栈的深度(栈帧数量)public void stackLeak() throws InterruptedException{//int a=500;//int b=400;//int c=600;//int d=900;Thread.sleep(1);stacklength++;stackLeak();}public static void main(String[] args) {StackSOF oom=new StackSOF();try {oom.stackLeak();} catch (Throwable e) {System.out.println("stack length:"+oom.stacklength);e.printStackTrace();}}}
当定义上述a、b、c、d四个变量时,因为栈帧变大,但栈的容量不变(128k),所以栈的深度变小(约2481→1819)。
栈深度在大多情况下达到1000~2000是没有问题的

2、OutOfMemoryError:在扩展栈时无法申请到足够的内存空间
通过不断产生线程的方式可以产生内存溢出,并且为每个栈分配的内存越大,越容易溢出
每个线程分配到的栈容量越大,可以建立的线程数量就越少,建立线程时就越容易把剩下的内存耗尽。
通过减少内存的方式来解决内存溢出:
如果建立过多的线程导致内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,只能通过减少栈容量或减少最大堆容量来换取更多的线程

方法区溢出

1、常量池导致方法区溢出
Jdk1.6时,常量池在方法区,因此new过多的字符串常量会导致常量池溢出

List<String> list=new ArrayList<String>();long i=0;while(true){   list.add(String.valueOf(++i).intern()); }

Jdk1.7时,常量池在堆内,不会产生上述效果
2、Hibernate、Spring等加载时,都会用到CGLIb等字节码技术,需要方法区的容量来保证动态创建的class,因此也可能导致方法区溢出


原创粉丝点击