• 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

  • 相关阅读:
    spring boot 报错 Failed to read HTTP message
    spring boot 之 Mybatis 配置
    Java生成xlsx格式的excel文件
    遍历FTP目录及下载
    Spring 报错
    git ssh key生成
    spring mvc原理
    LightOJ 1154
    Light OJ 1153
    入栈出栈的顺序问题
  • 原文地址:https://www.cnblogs.com/ericli-ericli/p/13034709.html
Copyright © 2020-2023  润新知