Redian新闻
>
Java 内部类有坑,100 % 内存泄露!

Java 内部类有坑,100 % 内存泄露!

公众号新闻
今天给大家分享一种,Java内部类使用不当导致的内存泄露问题,最终导致内存溢出!希望能够帮助到大家!



1

简介


说明


本文介绍 Java 内部类持有外部类导致内存泄露的原因以及其解决方案。


为什么内部类持有外部类会导致内存泄露?


非静态内部类会持有外部类,如果有地方引用了这个非静态内部类,会导致外部类也被引用,垃圾回收时无法回收这个外部类(即使外部类已经没有其他地方在使用了)。


解决方案


  • 不要让其他的地方持有这个非静态内部类的引用,直接在这个非静态内部类执行业务。

  • 将非静态内部类改为静态内部类。内部类改为静态的之后,它所引用的对象或属性也必须是静态的,所以静态内部类无法获得外部对象的引用,只能从 JVM 的 Method Area(方法区)获取到static类型的引用。



2

为什么要持有外部类


Java 语言中,非静态内部类的主要作用有两个:


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

  • 当内部类持有外部类时,它就可以直接使用外部类中的变量了,这样可以很方便的完成调用,如下代码所示:


package org.example.a;

class Outer{
    private String outerName = "Tony";

    class Inner{
        private String name;

        public Inner() {
            this.name = outerName;
        }
    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}


但是,静态内部类就无法持有外部类和其非静态字段了。


比如下边这样就会报错:


package org.example.a;

class Outer{
    private String outerName = "Tony";

    static class Inner{
        private String name;

        public Inner() {
            this.name = outerName;
        }
    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}


报错:




3

实例:持有外部类


代码


package org.example.a;

class Outer{
    class Inner {

    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}


断点调试


可以看到:内部类持有外部类的对象的引用,是以“this$0”这个字段来保存的。




4

实例:不持有外部类

 

代码


package org.example.a;

class Outer{
    static class Inner {

    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}


断点调试


可以发现:内部类不再持有外部类了。




5

实例:内存泄露

 

简介


若内部类持有外部类的引用,对内部类的使用很多时,会导致外部类数目很多。此时,就算是外部类的数据没有被用到,外部类的数据所占空间也不会被释放。


本处在外部类存放大量的数据来模拟。


代码


package org.example.a;

import java.util.ArrayList;
import java.util.List;

class Outer{
    private int[] data;

    public Outer(int size) {
        this.data = new int[size];
    }

    class Innner{

    }

    Innner createInner() {
        return new Innner();
    }
}

public class Demo {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        int counter = 0;
        while (true) {
            list.add(new Outer(100000).createInner());
            System.out.println(counter++);
        }
    }
}


测试


可以看到:运行了八千多次的时候就内存溢出了。



我换了一台 mac 电脑,4000 多就内存溢出了。



6

不会内存泄露的方案

 

简介


内部类改为静态的之后,它所引用的对象或属性也必须是静态的,所以静态内部类无法获得外部对象的引用,只能从 JVM 的 Method Area(方法区)获取到 static 类型的引用。


代码


package org.example.a;

import java.util.ArrayList;
import java.util.List;

class Outer{
    private int[] data;

    public Outer(int size) {
        this.data = new int[size];
    }

    static class Inner {

    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        int counter = 0;
        while (true) {
            list.add(new Outer(100000).createInner());
            System.out.println(counter++);
        }
    }
}


测试


可以发现:循环了四十多万次都没有内存溢出。



来源:knife.blog.csdn.net/article/details/121108201


推荐

准确率 99.9% 的离线IP地址定位库

你知道Java中的回调机制吗?

再见了,UUID !推荐一种更好的替代

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持我们吧!

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
宛如末日!美国突发万吨致癌物泄露!大量动物死亡、毒云漫天、民众恐慌!报道记者却被捕台湾地区华航郭台铭、林志玲、小S等会员信息泄露,华航:未确认泄露源头Weee出!事!华人常用网购网站1100万用户数据泄露!难怪最近这么多杀猪盘短信抓狂!俄亥俄事件后,美国又一起危险品泄露!公路封锁民众逃离…每秒1000000000000000000次运算!Cerebras新超级计算机打造世界最大1350万核心AI集群核聚变反应能量增益首次实现!人类有望进入更高层次文明重返,犹如重生;重见,倍感亲近。。。。美国发现奥密克戎毒性变弱的真正原因,人类有望彻底消灭新冠病毒!姓名地址生日全泄露!全美3700人再次“打赤膊” T-Mobile又被盗2023年3月绿卡排期两类有所推进 俄亥俄环境问题和居民健康成焦点重大!澳洲Medibank用户信息再遭泄露!黑客扬言:不给钱“周五继续”!新州HSC成绩今晨突然意外泄露!部分学生可提前查到成绩!去年已出现过类似事件…23年3月绿卡排期: 两类有所推进,这类出现倒退!换工记,在911呼叫中心工作江歌遗体照遭泄露!埋了6年的真相彻底反转?江秋莲,终于还是瞒不住了……宛如末日!美国突发万吨致癌物泄露!德国指挥家的中国妻子维州知名科技公司数据泄露!服务客户超1000家,包括维州政府澳洲知名科技公司数据泄露!服务客户超1000家,包括维州政府宛如末日!美国突发万吨致癌物泄露!大量动物死亡、毒云漫天悉尼机场紧急疏散旅客,出现气体泄露!两架国际航班被迫改道!持续发酵!美国火车出轨万吨致癌物泄露!最新后续来了,远比想象的更糟糕...崩溃!又一澳知名零售商被黑客入侵!客户隐私信息再次泄露!华人快自查!本想治白血病,意外治愈了艾滋!人类有望战胜绝症QS 2024世界大学排名提前泄露!英美高校大乱斗,引爆留学生圈俄版百度44.7G源码泄露!遭前员工背刺,涉及搜索地图打车电商等所有主要服务23年3月绿卡排期: 两类有所推进 这类出现倒退奇特的病人案例包凡的江湖,有坑ThreadLocal 搭配线程池使用造成内存泄漏的原因和解决方案2023年3月美国移民排期:两类有所推进 这类出现倒退Medibank更多隐私数据被泄露!总理也卷入!避免受骗,记好这五点!日投降后毛泽东赴重庆国共谈判热搜第一!美国俄亥俄州火车脱轨,致剧毒化学物泄露!动物大量死亡,居民头晕恶心!970万澳人中招!Medibank遭受特大信息泄露!华人该如何应对?你需要知道这些!
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。