内存溢出的预防及解决汇总

内存溢出是一个非常隐式的问题,经过相关资料的查询,先总结一下内存溢出的关键字:what(溢出表现)、origin(内存分配及回收)、where(溢出类型)、why(泄露原因)、how(预防及解决方案)。

一、what(溢出表现)

1. 服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;

2. 服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;

3. 服务器经常做 Full GC(Garbage Collection),而且时间很长,大约需要 30-40秒,应用服务器在做 Full GC的时候是不响应客户的交易请求的,非常影响系统性能。

4. 服务器的内存占用不是锯齿形波动,而是趋势向上,最后宕机。

二、origin(起源)

1. 内存溢出是指无法回收的内存积攒过多或者正在使用的内存过多,最终导致程序运行需要的内存大于虚拟机所能提供的最大内存,从而导致内存溢出。

因此,为了解决这个问题,从抽丝剥茧的角度来看,首先第一步需要明白起源,即明白内存分配以及回收的方式:

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

我觉得这一段话说的比较准确,总结起来就是:1.内存的分配及回收基本都可以交由程序静默进行,释放不了的核心在于引用还在。

2. 那么什么时候进行垃圾回收(分为Scavenge GC 跟 Full GC)呢?

2.1 Scavenge GC 主要集中在 Eden 园区,一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。

2.2 Full GC。速度很慢,对整个堆进行整理,包括Young、Tenured和Perm。引起 Full GC 的方式有:老年代被写满,持久代被写满以及System.gc()被显示调用。

三、where(主要溢出类型)

下一步我们继续关注主要在什么位置有可能内存溢出:

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

堆是垃圾回收关注的重点,如果在垃圾回收之间 Java 虚拟机创建了过多的对象,虚拟机分配到堆内存的空间已经满了,那么就会报这个错误。

2. Java.lang.OutOfMemoryError: PermGen space (永久区溢出)

如果说堆是给我们程序员使用的话,那么非堆就是给JVM自己使用的,非堆主要存在类的基本信息,他与堆的不同之处在于非堆中在运行期间GC不会释放空间。按照该异常的原义,指的是程序中使用了大量的jar或class,使java虚拟机装载类的空间不够(注意这时候是MaxPermSize较小)。

四、why(泄漏原因)

根据时间顺序,我们大致可以总结如下:

1. 启动参数内存值设定的过小,无法加载过大的包;

2. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

3. 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;

4. 代码中存在死循环或循环产生过多重复的对象实体;

5. 使用的第三方软件中的BUG;

6. 注意其他不健壮的代码原因;

6.1 注意无引用对象的及时释放;

6.2 无法避免的大量字符串处理,尽量使用 StringBuffer 而非 String,原因是每一个 String 都需要占用一块内存空间;

6.3 注意静态变量的使用,因为静态变量是全局变量,不会被回收;

6.4 注意大对象的创建及使用,注意显示声明极大的数组对象;

6.5 注意循环体体内的对象创建;

6.6 注意是否一次性查询出来大量的数据;

6.7 检查List及Map是否有对象的引用一直存在;

五、how(解决方案及预防方案)

一般来说,系统稳定之后,内存的使用是保持在一定水平的,如果发现内存的使用随时间的增长而呈现线性的增长,那么就有可能说明正在内存泄露。

一般处理的思路,跟以上原因其实一一对应:

1. 增大JVM的启动内存,-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m;

2. 检查错误日志;

3. 代码层面的检查(参见第四大点的原因);

4. 使用检查工具,Optimizeit Profiler、JProbe Profiler等等。这些工具的主要点都会聚焦在追踪对象的申请、释放等动作,将内存管理的所有信息进行统计然后可视化,根据这些信息,可以追踪到上述三个步骤仍然无法检查到的泄露对象。

文章参考:

1.《jvm垃圾回收是什么时候触发的? 垃圾回收算法? 都有哪些垃圾回收器》http://blog.csdn.net/sunny243788557/article/details/52797088

2.《Java内存溢出的详细解决方案》http://blog.csdn.net/tototuzuoquan/article/details/25591923

3.《java中三种常见内存溢出错误的处理方法》http://outofmemory.cn/java/OutOfMemoryError/PermGen-space-Java-heap-space-unable-create-new-native-thread

4.《Java中垃圾回收有什么目的?什么时候进行垃圾回收?》https://zhidao.baidu.com/question/2204377803050672708.html

5.《 Java内存溢出详解及解决方案》http://blog.csdn.net/xianmiao2009/article/details/49254391

时间: 2024-10-14 05:20:18

内存溢出的预防及解决汇总的相关文章

myeclipse内存溢出的N个解决办法

MyEclipse内存溢出解决方法 1.修改eclipse.ini 在Myeclipse安装目录下G:\MyEclipse8.5\Genuitec\MyEclipse 8.5有一个myeclipse.ini配置文件,设置如下: -vmargs-Xmx512m-XX:MaxPermSize=256m-XX:ReservedCodeCacheSize=64m2.设置Default VM Arguments 在myEclipse中,打开Windows-> Preferences->Java->

几种内存溢出的类型及解决思路

相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各类问题经验的积累以及对问题根源的探索,终于有了一个比较深入的认识. 在解决java内存溢出问题之前,需要对jvm(java虚拟机)的内存管理有一定的认识.jvm管理的内存大致包括三种不同类型的内存区域:Permanent Generation space(永久保存区域).Heap space(堆区域).Java Stacks(Java栈).其中永久保存区域主要存放Class

tomcat内存溢出原因分析与解决

网上有很多的介绍但都不全面,本文综合了几篇文章共同组从. 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存原因是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种情况: 1.OutOfMemoryError: Java heap space 2.OutOfMemoryError: PermGen space 3.OutOfMemoryError: unable to create new native thread. 对于前两种

Java 出现内存溢出的定位以及解决方式

在上一节中Java虚拟机内存分布   说了Java虚拟机中分为五个区域,并且也知道了在Java程序计数器区域不会出现OOM(OutOfMemeryError),那么下面就对除了程序计数器以外的四个区域出现OOM的原理以及解决方式进行讲解. 1.Java虚拟机栈与本地方法栈 栈的大小控制参数时 -Xss. Java虚拟机在栈中定义了两种异常,StrackOverFlowError和OutOfMemeryError.当请求栈的深度大于java虚拟机所允许的最大深度则抛出StrackOverFlowE

Android加载大量图片内存溢出的三种解决办法

方法一: 在从网络或本地加载图片的时候,只加载缩略图. 这个方法的确能够少占用不少内存,可是它的致命的缺点就是,因为加载的是缩略图,所以图片失真比较严重,对于对图片质量要求很高的应用,可以采用下面的方法. 方法二: 运用JAVA的软引用,进行图片缓存,将经常需要加载的图片,存放在缓存里,避免反复加载. 方法三: 及时销毁不再使用的Bitmap对象. if (bitmap != null && b!itmap.isRecycled()){ bitmap.recycle(); bitmap =

Java中OutOfMemoryError(内存溢出)的情况及解决办法

java.lang.OutOfMemoryError: Java heap space // TODO Auto-generated method stub Vector v = new Vector(10); for (int i = 1; i<1000000000; i++) {Object o = new Object(); v.add(o); o = null; } 因为每一次生成一个新的对象,都会放入到堆区(heap)里面,所以堆区的空间肯定就不够了. 那就只能去修改循环的次数

内存溢出(OOM)and内存泄露---及其解决

那么问题来了 什么是内存溢出out of memory?(OOM) 已有数据超出其分配内存所能存储的范围 比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. 什么是内存泄露memory leak? 指程序在申请内存后,无法释放已申请的内存空间, 他们到底啥关系? 一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光.memory leak会最终会导致out of memory! 哪些情况经常导致内存溢出??如何解决呢?? 当项目中包含大量图片

Java虚拟机系列(三)---内存溢出情况及解决方法

因为Java虚拟机内存有堆内存.方法区.虚拟机栈.本地方法栈和程序计数器五部分组成,其中程序计数器是唯一一块不会发生内存溢出异常的内存区,所以只有四类内存区可能发生内存溢出异常,其中虚拟机栈和本地方法栈都是Java方法执行的内存模型,所以它们的异常发生情况几乎相同,另外,在方法区中.又有一块内存是常量池,所以内存溢出的情况可分为Java堆溢出.虚拟机栈和本地方法栈溢出.方法区和运行时常量池溢三种情况. 一.Java堆溢出 1.产生的原因:因为堆中存放的是对象实例和数组,所以当对象数量>最大堆容量

内存溢出和内存泄漏的区别、产生原因以及解决方案 转

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. 内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光. memory leak会最终会导致out of memory! 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产