java内存溢出

内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。Java的内存管理就是对象的分配和释放问题。在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾收集器(Garbage Collection,GC)完成的,程序员不需要通过调用GC函数来释放内存,因为不同的JVM实现者可能使用不同的算法管理GC,有的是内存使用到达一定程度时,GC才开始工作,也有定时执行的,有的是中断式执行GC。但GC只能回收无用并且不再被其它对象引用的那些对象所占用的空间。 Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就作为垃圾回收。 

 

常见几种内存溢出原因: 

  • 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  • 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
  • 代码中存在死循环或循环产生过多重复的对象实体;
  • 使用的第三方软件中的BUG;
  • 启动参数内存值设定的过小;

 

常见的三种Java内存溢出:

  • java.lang.OutOfMemoryError: Java heap space(Java堆溢出)
  • java.lang.OutOfMemoryError: PermGen space(PermGen space溢出)
  • java.lang.StackOverflowError(栈溢出)

 

java.lang.OutOfMemoryError: Java heap space(Java堆溢出)

JVM在启动的时候会自动设置JVM Heap的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存。可以利用JVM提供的-Xmn -Xms -Xmx等选项进行设置。Heap的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的时间是用于GC,且可用的Heap size 不足2%的时候将抛出此异常信息。

 

以下示例不断创建对象以模拟堆溢出:


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

Java heap space溢出信息

 

可以手动设置JVM Heap(堆)的大小以解决。修改 TOMCAT_HOME/bin/catalina.sh ,在顶部加入:

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"

-XX:MaxNewSize=size 设定新生代占整个堆内存的最大值。

 

java.lang.OutOfMemoryError: PermGen space(PermGen space溢出)

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域。为什么会内存溢出?这是由于这块内存主要是被JVM存放Class和Meta信息的,Class在被Load的时候被放入PermGen space区域,它和存放Instance的Heap区域不同,sun的 GC不会在主程序运行期对PermGen space进行清理,所以如果你的APP会载入很多CLASS的话,就很可能出现PermGen space溢出。
以下代码示例不断创建新的class以模拟(需要cglib和asm相关jar包):

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Test {
	static class MethodAreaOomObject {
	}

	public static void main(String[] args) {
		while (true) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(MethodAreaOomObject.class);
			enhancer.setUseCache(false);
			enhancer.setCallback(new MethodInterceptor() {
				public Object intercept(Object obj, Method method,
						Object[] args, MethodProxy proxy)
						throws Throwable {
					return proxy.invoke(obj, args);
				}
			});
			enhancer.create();
		}
	}
}


PermGen space溢出信息

 

可以手动设置MaxPermSize大小以解决。修改TOMCAT_HOME/bin/catalina.sh,在顶部加入:

JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128M"

-XX:MaxNewSize=size 设定 Perm(俗称方法区)占整个堆内存的最大值。

 

java.lang.StackOverflowError(栈溢出)

JVM依然是采用栈式的虚拟机,这个和C和Pascal都是一样的。函数的调用过程都体现在堆栈和退栈上了。调用构造函数的 “层”太多了,以致于把栈区溢出了。通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要 1K的空间(这个大约相当于在一个C函数内声明了256个int类型的变量),那么栈区也不过是需要1MB的空间。通常栈的大小是1-2MB的。通常递归也不要递归的层次过多,很容易溢出。

 

以下代码示例不断递归调用某一函数以模拟栈溢出:

public class Test {
	public static void main(String[] args) {
		new Test().test();
	}

	public void test() {
		test();
	}
}

StackOverflowError溢出信息

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值