注意避坑!Java 内部类持有外部类会导致内存泄露。。。

这篇具有很好参考价值的文章主要介绍了注意避坑!Java 内部类持有外部类会导致内存泄露。。。。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

说明

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

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

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

解决方案

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

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

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

为什么要持有外部类

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);
    }
}

报错:

注意避坑!Java 内部类持有外部类会导致内存泄露。。。

实例:持有外部类

代码

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”这个字段来保存的。

注意避坑!Java 内部类持有外部类会导致内存泄露。。。

实例:不持有外部类

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

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);
    }
}

断点调试

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

注意避坑!Java 内部类持有外部类会导致内存泄露。。。

实例:内存泄露

简介

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

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

代码

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++);
        }
    }
}

测试

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

注意避坑!Java 内部类持有外部类会导致内存泄露。。。

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

注意避坑!Java 内部类持有外部类会导致内存泄露。。。

不会内存泄露的方案

简介

内部类改为静态的之后,它所引用的对象或属性也必须是静态的,所以静态内部类无法获得外部对象的引用,只能从 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++);
        }
    }
}

测试

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

注意避坑!Java 内部类持有外部类会导致内存泄露。。。

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

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!文章来源地址https://www.toymoban.com/news/detail-707950.html

到了这里,关于注意避坑!Java 内部类持有外部类会导致内存泄露。。。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 避坑之路 —— 前后端 json 的注意问题

    当我们在进行开发项目的时候,在前后端需要进行数据之间的传输,那么就会需要到json。而json算是字符串中的一种 1.先说一下前端的, 其实这两种都是表示前端希望能收到后端json这样的数据格式,那么我们在后端就需要注意将数据进行转换为json进行返回 2.后端 这里我就说一

    2024年02月09日
    浏览(36)
  • java根据身份证号计算持有者年龄--超容易

    主要思路很简单: 1.通过当前年份和用户出生年份相减计算出age :用户当年还没过生的话,age要减一。 2.在身份证截取根据“ 月日 ”拼接成开头可以为0的 四位数int值 。根据 当前月日 值和用户 出生月日 对比大小,一步判断age是否要减一。避免了月份判断月份相同等和日期

    2024年02月12日
    浏览(39)
  • 内部表与外部表——头歌

    任务描述 本关任务:创建外部表,并导入数据。 相关知识 为了完成本关任务,你需要掌握:1.表的各种操作。 内部表和外部表 Hive 默认创建内部表(managed table),存储位置在 hive.metastore.warehouse.dir 设置,默认位置是 /user/hive/warehouse。导入数据到内部表的时候是将文件剪切(

    2024年02月08日
    浏览(32)
  • android内部存储和外部存储

    我们在开发Android应用的过程中,避免不了要用到数据持久化技术,所谓的数据持久化就是将RAM中的瞬时数据保存到ROM中,保证在App退出或者手机关机后数据不会丢失。我们常用的数据持久化的方式有文件存储,数据库存储,SharedPreference存储等。在window中,当我们存储文件或

    2024年02月09日
    浏览(45)
  • ’yolo‘不是内部或外部命令

    2024年04月15日
    浏览(54)
  • Hive内部表及外部表

    内部表,也叫托管表,是Hive在创建表时的默认表。 特点:在内部表被删除后,表的元数据和表数据都从HDFS中完全删除 create table if not exists 表名( 字段名称 字段类型, ... 字段名称 字段类型 ) comment 表的注释 raw format delimited fields terminated by \\\'分隔符\\\'  #列以\\\'分隔符\\\'分割 line 

    2024年02月05日
    浏览(34)
  • Hive内部表和外部表

    表分类 在Hive中,表类型主要分为两种 第一种: 内部表 也叫管理表 表目录会创建在集群上的{hive.metastore.warehouse.dir}下的相应的库对应的目录中。 默认创建的表就是内部表 第二种: 外部表 外部表需要使用\\\"external\\\", 外部表会根据创建表时LOCATION指定的路径来创建目录,

    2024年02月15日
    浏览(41)
  • Android外部存储与内部存储详解

    内部储存(内部存储的文件夹其他应用和用户无法直接访问,可以用于存放敏感数据。app进行数据清理或卸载可以清理外部存储和内部存储下的所有文件目录, 不需要读写权限 ) getFilesDir() /data/data/包名/files 或者 /data/user/0/包名/files getCacheDir() /data/data/包名/cache 或者 /data/u

    2024年04月09日
    浏览(60)
  • docker容器内部可以访问,外部无法访问

    外部无法访问nginx :将docker容器部署后台运行后,发现无法通过ip(宿主机ip地址,可以通过ifconfig去查看eno***的inet地址便可,也可直接填写localhost):80(例如: localhost:80 )去访问却发现访问失败 内部访问成功 :于是我想先看看docker内部是否可以访问得到,先检查nginx是否开

    2023年04月08日
    浏览(81)
  • 避坑:.NET内存泄露的几种情况

    内存“泄露”是开发中常见的问题之一,它会导致应用程序占用越来越多的内存资源,最终可能导致系统性能下降甚至崩溃。软件开发者需要了解在程序中出现内存泄露的情况,以避免软件出现该的问题。 什么是内存“泄露”? 内存泄露是申请了内存空间的变量一直在占用

    2024年02月11日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包