内存溢出分析总结
Posted 陈晓婵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存溢出分析总结相关的知识,希望对你有一定的参考价值。
堆溢出
堆中一般存放对象、数组等大对象,当堆中的对象达到堆的最大容量限制后,就会产生内存溢出
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,因此也可能导致方法区溢出
以上是关于内存溢出分析总结的主要内容,如果未能解决你的问题,请参考以下文章
五种内存溢出案例总结:涵盖栈深度溢出永久代内存溢出本地方法栈溢出JVM栈内存溢出和堆溢出