内存泄漏:对象已经不被程序使用 但是无法被GC回收。内存泄漏会导致内存溢出。
1.静态集合类
static HashMap hashMap = new HashMap();
这类对象的生命周期与JVM周期一致,不会被回收 导致他们包含的元素也一直不会被回收。
2.单例模式
与静态集合类原因相似 由于单例模式中对象为静态 ,当他持有外部对象的引用时,外部对象也无法被回收。
3.内部类持有外部类
public class classA {
private String privateA;
public String publicA;
public String getPrivateA() {
return privateA;
}
public void setPrivateA(String privateA) {
this.privateA = privateA;
}
public String getPublicA() {
return publicA;
}
public void setPublicA(String publicA) {
this.publicA = publicA;
}
class B{
private String privateB;
public String publicB;
public String getPrivateB() {
//内部类调用外部类方法
return getPrivateA();
}
public void setPrivateB(String privateB) {
this.privateB = privateB;
}
public String getPublicB() {
return publicB;
}
public void setPublicB(String publicB) {
this.publicB = publicB;
}
}
public static class C{
private String privateC;
public String publicC;
public String getPrivateC() {
return privateC;
}
public void setPrivateC(String privateC) {
this.privateC = privateC;
}
public String getPublicC() {
return publicC;
}
public void setPublicC(String publicC) {
this.publicC = publicC;
}
}
public static void main(String[] args) {
classA a = new classA();
a.setPrivateA("aaa");
classA.B b= a.new B();
String s = b.getPrivateB();
System.out.println(s);
}
}
javac编译java文件
class classA$B {
private String privateB;
public String publicB;
classA$B(classA var1) {
this.this$0 = var1;
}
内部类的构造函数中存储了一个外部类的引用 这也是内部类能调用外部类方法的原因。因此即使外部类使用完毕 但如果内部类还没有释放。则外部类也不会被回收 造成内存泄漏。
public class classA$C {
private String privateC;
public String publicC;
public classA$C() {
}
4.各种数据库连接
IO 文件流等不关闭close
5.变量的作用域不合理
msg只在receiveMsg中使用 则尽量在此方法中定义。
6.改变hash值
泄漏行为:对参与Hash值计算的属性 重新赋值。因为会根据HashMap去计算对象的存放位置 本来针对同一个对象不能重复存放 但是由于重新修改了他的某个属性导致Hash值改变 那就会再次被存在。同时第一次赋值的对象也取不到了。
public class ChangeHashCode1 {
public static void main(String[] args) {
HashSet<Point> hs = new HashSet<Point>();
Point cc = new Point();
cc.setX(10);//hashCode = 41
hs.add(cc);
cc.setX(20);//hashCode = 51 此行为导致了内存的泄漏
System.out.println("hs.remove = " + hs.remove(cc));//false
hs.add(cc);
System.out.println("hs.size = " + hs.size());//size = 2
System.out.println(hs);
}
}
class Point {
int x;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Point other = (Point) obj;
if (x != other.x) return false;
return true;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
'}';
}
}
7.缓存泄漏
使用WeakHashMap 弱引用。一旦GC即回收。
public class WeekHash {
public static void main(String[] args) {
String a = new String("a");
String b = new String("b");
Map map = new HashMap();
map.put(a, "aaa");
map.put(b, "bbb");
Map weakmap = new WeakHashMap();
weakmap.put(a, "aaa");
weakmap.put(b, "bbb");
map.remove(a);
a = null;
b = null;
System.gc();
Iterator i = map.entrySet().iterator();
while (i.hasNext()) {
Map.Entry en = (Map.Entry) i.next();
System.out.println("map:" + en.getKey() + ":" + en.getValue());
}
Iterator j = weakmap.entrySet().iterator();
while (j.hasNext()) {
Map.Entry en = (Map.Entry) j.next();
System.out.println("weakmap:" + en.getKey() + ":" + en.getValue());
}
}
}
/*结果是 HashMap和WeakHashMap中都只包含b
解释:对于a对象而言,当HashMap remove掉并且将a指向null后,除了WeakHashMap中还保存a外已经没有指向a的指针了,所以WeakHashMap会自动舍弃掉a,而对于b对象虽然指向了null,但HashMap中还有指向b的指针*/
示例代码转自 链接:https://blog.csdn.net/u013467442/article/details/105826778
8.ThreadLocal内存泄漏
每个thread中都存在一个map(ThreadLocalMap), map的类型是ThreadLocal.ThreadLocalMap. Map中的key为一个threadlocal实例. 这个Map的确使用了弱引用,不过弱引用只是针对key. 每个key都弱引用指向threadlocal. 当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收. ThreadLocal Ref被回收了,才会导致value内存泄露的发生。但是,我们的value却不能回收,因为存在一条从current thread连接过来的强引用. 只有当前thread结束以后, current thread就不会存在栈中,强引用断开, Current Thread, Map, value将全部被GC回收.
最要命的是线程对象不被回收的情况,这就发生了真正意义上的内存泄露。比如使用线程池的时候,线程结束是不会销毁的,会再次使用的。就可能出现内存泄露.
每次使用完ThreadLocal都调用它的remove()方法清除数据
转自链接:https://www.jianshu.com/p/1b32d72dd08b