内存溢出分析总结

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栈内存溢出和堆溢出

五种内存溢出案例总结:涵盖栈深度溢出永久代内存溢出本地方法栈溢出JVM栈内存溢出和堆溢出

Tomcat_Java Web_内存溢出总结

Java内存溢出问题总结

转:Tomcat内存溢出的三种情况及解决办法分析

JVM的OOM分析总结