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
    评论
Java内存溢出指的是在Java程序运行过程中,因为申请的内存超出了可用内存的限制,导致程序终止的现象。下面是一些排查Java内存溢出问题的方法: 1.确定是否是内存溢出问题:查看程序的错误日志或异常信息,如果有OutOfMemoryError的错误信息,可以确定是内存溢出问题。 2.分析问题发生的位置:追踪错误日志或异常堆栈,定位到代码中可能导致内存溢出的地方,比如不断创建对象、大量递归调用等。 3.查看程序的内存使用情况:可以使用Java的内存分析工具,如jmap、jstat等,查看程序运行时的内存使用情况,包括堆内存和非堆内存的使用情况。 4.检查代码中是否有资源未释放:Java中需要手动释放的资源包括文件流、数据库连接等,如果资源没有正确释放,会导致内存泄漏,最终导致内存溢出。 5.检查是否存在循环引用:循环引用指的是多个对象相互引用,导致垃圾回收器无法回收它们,最终导致内存溢出。可以使用内存分析工具来分析程序中是否存在循环引用的情况。 6.调整JVM参数:可以通过调整JVM的参数来增加可用内存,比如增加堆内存的大小。可以使用命令行参数'-Xms'和'-Xmx'来指定初始堆大小和最大堆大小。 7.优化代码:检查代码中是否存在不必要的对象创建、频繁的垃圾回收等问题,优化程序的设计和算法,减少内存使用。 8.升级JDK版本:某些JDK版本中可能存在内存泄漏或其他内存相关的问题,升级到最新的JDK版本可以解决一些内存溢出问题。 总之,排查Java内存溢出问题需要分析错误日志、查看内存使用情况、检查代码和资源释放等等,找出问题的根源并及时修复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值