使用双花括号初始化集合,可别这么干
本文最后更新于 1028 天前,其中的信息可能已经有所发展或是发生改变。

Double Brace Initialization should not be used

前言

最近在修改sonar问题时,发现有人使用双花括号初始化集合,提示可能发生内存泄漏。这种初始化方式倒是见过,只知道是使用了匿名内部类,但没有意识到这个问题。

实测

A

提供两种Map的初始化方法,为了观察是否被回收,重写了finalize方法。

public class A {

    private String name;

    public A(String name) {
        this.name = name;
    }

    public Map<String, String> getMap() {
        return new HashMap<String, String>() {
            private static final long serialVersionUID = -3309655755403147761L;

            {
            put("name", name);
        }};

    }

    public Map<String, String> getMap1() {
        return new HashMap<String, String>();
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("Thread name: " + Thread.currentThread().getName() + " Object: " + this.name + " Gc happen");
        super.finalize();
    }
}

B

有个map成员变量

public class B {

    private Map<String, String> map;

    public B(Map<String, String> map) {
        this.map = map;
    }
}

Test

public class Test {
    public static void main(String[] args) throws InterruptedException {
        A a = new A("bob");
        final B b = new B(a.getMap());
        System.out.println("访问外部类对象的属性:" + b.getMap().get("name"));
        a = null;
        System.gc();
        Thread.sleep(1000);

        A a1 = new A("sandy");
        final B b1 = new B(a1.getMap1());
        a1 = null;
        System.gc();
        Thread.sleep(1000);
    }
}

输出

访问外部类对象的属性:bob
Thread name: Finalizer Object: sandy Gc happen

分析

匿名内部类持有外部类对象引用

双花括号初始化时,可以直接使用外部类对象的成员name。当然这只是表面,接下来我们从字节码的层面看看到底怎么回事。

使用了匿名内部类

  • 双花括号初始化的方法

image-20210910122144165

  • 非双花括号初始化的方法

image-20210910122213745

编译后产生的文件

image-20210910115942132

可以发现,多了一个内部类:A$1.class。

查看内部类字节码

image-20210910121241738

  1. 拥有一个外部类的成员变量
  2. 通过构造方法传入了外部类对象的引用
  3. 将外部类对象的引用赋值给成员变量
  4. 执行我们写的put方法
  5. 内部类继承于HashMap

发生了内存泄漏

使用非双花括号初始化map的sandy被回收了,而使用双花括号初始化map的bob却没有被回收。原因是b1的map和a1没啥关系,a1=null后,根不可达,所以被回收了。b的map持有a的引用,所以a=null后,还有强引用,依然根可达,不能回收,最终发生内存泄漏。

作者:Yuyy
博客:https://yuyy.info

评论

  1. Devin
    Windows Chrome
    3年前
    2021-9-10 15:38:19

    阿里老兵带我飞

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇