(Java学习笔记)Java的内存泄漏
关键词:java、内存泄漏
内存泄漏定义
传统定义:一个对象不再被程序使用,但它所占用的内存没有得到及时的释放,导致内存使用量随着时间不断增加,最终导致程序崩溃。
Java内存泄漏:java采用自动垃圾回收(GC),一般情况不会发生传统意义上的内存泄漏。我们常说的内存泄漏指的是代码中无意延长了对象的生命周期。
内存泄漏常见例子
不合理的作用域
变量定义的作用域远大于其使用范围,甚至程序整个生命周期都不会释放内存(静态变量)。变量定义时注意这个变量作用的地方,如果超出作用域需要及时设置为null。
例子:
A对象引用B对象,A对象的生命周期(t1-t4)比B对象生命周期(t2-t3)长的多。当B对象没有被应用程序使用之后,A对象仍然在引用着B对象。这样GC没法将B对象从内存中溢出,从而导致这期间内存泄漏。
public void A() {
B b = new B(); --------A引用B对象
b.start(); --------B对象执行完毕
for () { --------此部分开始做其他逻辑,跟B对象没有关系
…
}
…
}
应修改为
public void A() {
B b = new B(); --------A引用B对象
b.start(); --------B对象执行完毕
b = null; --------把b引用地址指向未null,使GC判断实例化空间可以回收
for () { --------此部分开始做其他逻辑,跟B对象没有关系
…
}
…
}
资源未关闭造成的内存泄漏
未关闭的流、网络、文件、数据库连接等没有手动关闭会造成内存泄漏。
try {
Connection conn = ConnectionFactory.getConnection();
…
…
} catch (Exception e) {
e.printStacktrace();
}
应修改为
try {
Connection conn = ConnectionFactory.getConnection();
…
…
} catch (Exception e) {
e.printStacktrace();
} finally {
conn.close(); --------需要手动关闭
}
hashMap key值使用对象时造成内存泄漏
public void leak() {
Map map = new HashMap();
map.put(new Leak(), 1); --------此部分会造成内存泄漏(Leak类是自定义的类)
}
原因:自定义的Leak类没有重写hashCode()、equals()方法
分析1:如果不重写hashCode(),map.put()时不得不调用Object的hashCode()方法。Object的hashCode()方法计算的hash值是该对象的内存地址。每个对象的内存地址不可能一样,所以,需要重写hashCode()方法使map.put()调用重写的hasCode()获取对象值的hash值。
分析2:如果不重写equals()方法,会调用Object类的equals()。Object类的equals()比较的是内存地址,所以不同的对象不可能相同。需要重写equals()方法比较对象值。
内部类
内部类默认持有外部类的引用。(以构造方法的形式 this)所以引用内部类时外部类也会被引用。GC无法回收外部类。
public class Entity {
…
class Nbc {
… --------编译时此部分默认会有public Nbc(Entity entity)
}
}