内存泄漏的八大情况

内存泄漏:对象已经不被程序使用 但是无法被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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值