java踩坑记之双花括号初始化实例导致内存泄露

2020-12-26 22:28

阅读:457

标签:https   ret   ice   asList   参考   问题   class   回收   rgs   

问题描述

先来看一段代码:

public class DoubleBracesTest {
    private String key = "key";
    private String value="value";
    public Map test(String[] args){
        Map map = new HashMap() {{
            put("k", "v");
            put(key,value);
        }};
        return map;
    }
}

通过javac编译后,生成文件:DoubleBracesTest.class 和 DoubleBracesTest$1.class,确认上面的代码中的"{{"的方式写法,采用了内部类来实现的。

用IDEA查看 DoubleBracesTest$1.class :

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.util.HashMap;

class DoubleBracesTest$1 extends HashMap {
    DoubleBracesTest$1(DoubleBracesTest var1) {
        this.this$0 = var1;
        this.put("k", "v");
        this.put(this.this$0.key, this.this$0.value);
    }
}

其中的  this.this$0 = var1  代表内部类持有了外部类的引用。

对应的字节码:

技术图片

 

字节码中的 putfield这一行,这里表示有一个对DoubleBracesTest的引用被存在了 this$0 中,也就是说它持有了外部类的对象。

test方法返回一个map,如果被其他对象的属性所引用,GC时便不会回收此对象,从而导致内存泄漏!这个也是非静态内部类的主要缺点。

非静态内部类的优点

非静态匿名内部类持有外部类可以总结为以下两个作用 :

1.当匿名内部类只在外部类(主类)中使用时,匿名内部类可以让外部不知道它的存在,从而减少了代码的维护工作。

2.当匿名内部类持有外部类时,它就可以直接使用外部类中的变量了,这样可以很方便的完成调用。

改进方法

1、上述调用方法改成static方法

  匿名内部类是静态的之后,它所引用的对象或属性也必须是静态的了,因此就可以直接从 JVM 的 Method Area(方法区)获取到引用而无需持久外部对象了,也就不会持有外部类的引用了。

  但是后期难保不会有人将 static 关键字删掉,那样问题又会出现了!

2

使用集合工厂的 of 方法替代

Map map = new HashMap() {{
    put("k1", "v1");
    put("k2", "v2");
}};
替换成:
Map map= Map.of("k1", "v1", "k2", "v2");
 

 

List list = new ArrayList() {{
    add("aaa");
    add("bbb");
}};
替换成:
List list = new ArrayList(Arrays.asList("aaa","bbb"));

Stream API 替代

List list = new ArrayList() {{
    add("aaa");
    add("bbb");
}};
替换成
List list = Stream.of("aaa", "bbb").collect(Collectors.toList());

 

 

参考

https://www.ripjava.com/article/1291630596325408

https://www.cnblogs.com/wenbronk/p/7000643.html

https://cloud.tencent.com/developer/article/1632486

https://cloud.tencent.com/developer/article/1179625

https://hacpai.com/article/1498563483898

java踩坑记之双花括号初始化实例导致内存泄露

标签:https   ret   ice   asList   参考   问题   class   回收   rgs   

原文地址:https://www.cnblogs.com/ericli-ericli/p/13034709.html


评论


亲,登录后才可以留言!