1. 什么是内存溢出?
当前创建的对象的大小大于可用的内存容量大小,发生内存溢出。
2. 什么是内存泄露?
该回收的垃圾对象没有被回收,发生了内存泄露,垃圾对象越堆越多,
可用内存越来越少,若可用内存无法存放新的垃圾对象,就导致内存溢出。
内存泄露会导致内存溢出
3. 内存溢出的几种原因和解决办法
1.内存中加载的数据量过于庞大
,如一次从数据库取出过多数据。
解决方法:检查对数据库查询中,是否有一次获得全部数据的查询;
对于数据库查询尽量采用分页的方式查询。
2.集合类中有对对象的引用,使用完后未清空
,使得JVM不能回收。
解决方法:检查List、MAP等集合对象是否有使用完后,未清除的问题。
List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
3.代码中存在死循环
或循环产生过多重复的对象实体
。
解决方法:检查代码中是否有死循环或递归调用;
检查是否有大循环重复产生新对象实体。
4.启动参数内存值设定的过小
;
解决方法:修改JVM启动参数(-Xms,-Xmx),直接增加内存。
4. 内存泄漏的几种原因
4.1 静态集合类引起内存泄漏
静态集合的生命周期和 JVM 一致,所以静态集合引用的对象不能被释放。
public classOOM{
static List list =newArrayList();
public void oomTests(){
Object obj =new Object();
list.add(obj);
}
}
4.2 单例模式
和上面的例子原理类似,单例对象在初始化后会以静态变量的方式在
JVM 的整个生命周期中存在。如果单例对象持有外部的引用,
那么这个外部对象将不能被 GC 回收,导致内存泄漏。
4.3 忘记关闭数据库连接、IO、Socket等资源
数据连接、IO、Socket等连接创建的连接不再使用时,需要调用 close 方法关闭连接,只有连接被关闭后,GC 才会回收对应的对象(Connection,Statement,ResultSet,Session
)。
忘记关闭这些资源会导致持续占有内存,无法被 GC 回收。
try{
Connection conn = null;
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("url","","");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("....");
}catch(Exception e){
}finally{
//不关闭连接
}}
4.4 变量不合理的作用域
一个变量的定义作用域大于其使用范围,很可能存在内存泄漏;或不再使用对象没有及时将对象设置为 null,很可能导致内存泄漏的发生。
public class Simple{
Object object;
public void method1(){
object =newObject();
//...其他代码
//由于作用域原因,method1执行完成之后,
//object 对象所分配的内存不会马上释放
object = null;
}}
4.5 ThreadLocal 造成的内存泄漏
ThreadLocal 可以实现变量的线程隔离,但若使用不当,就可能会引入内存泄漏问题。