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

Posted Eric-Lee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java踩坑记之双花括号初始化实例导致内存泄露相关的知识,希望对你有一定的参考价值。

问题描述

先来看一段代码:

public class DoubleBracesTest {
    private String key = "key";
    private String value="value";
    public Map<String, String> test(String[] args){
        Map<String, String> 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<String, String> map= Map.of("k1", "v1", "k2", "v2");
 

 

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

Stream API 替代

List<String> list = new ArrayList() {{
    add("aaa");
    add("bbb");
}};
替换成
List<String> 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踩坑记之双花括号初始化实例导致内存泄露的主要内容,如果未能解决你的问题,请参考以下文章

小程序踩坑记之——花屏/重复渲染数据

技巧:Ubuntu踩坑记之网络配置哪里找

Groovy踩坑记之方法调用八层认识

vue踩坑记:属性报undefined错误

LeetCode小白算法成长记之双指针

如何用Java编写一段代码引发内存泄露