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

ElasticJob引发的Tomcat内存泄漏问题 这里记录一下遇到的一个tomcat memory leak的问题:一个使用了elastic job的webapp,在进行热部署的时候日志打印了内存泄漏异常。 前置知识点 在类使用完之后,如果满足下面的情况,类就会被卸载: 1.该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。 2.加载该类的ClassLoader已经被回收。 3.该类对应的java.lang.Clas 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:knife.blog.youkuaiyun.com


简介

「说明」

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

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

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

「解决方案」

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

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

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

为什么要持有外部类

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

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

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

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

报错:

e9a84ca629a7663dd2f7dc143cd9efc4.png

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

实例:持有外部类

「代码」

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

20e06ab1645612dada2655edc6edacc8.png

实例:不持有外部类

「代码」

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

「断点调试」

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

9c99fe67d325efb7fcb7d40fff10fe76.png

实例:内存泄露

「简介」

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

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

「代码」

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

「测试」

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

eaad106043152c3e4f0452066bae60fc.png

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

6baa23e04d4726bcc29caa5b330288ed.png

不会内存泄露的方案

「简介」

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

「测试」

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

113c974d1a01983c3be3fa897c761a9b.png

以上,希望能对大家在使用内部类时会有所帮助。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

49fe8bd9c28fa5da88470d1dd6db9b22.png

已在知识星球更新源码解析如下:

b118ea67053c0e0ad0404ffb4a27b68c.jpeg

ea98f5d62e7ca2ed31ee9d5d6db9b5c9.jpeg

0152e6f63d9e20715afe1d1140b3187d.jpeg

5520c6029b8011d7766fa8bfeb47c393.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
Pcileech(DMA)开源项目简述 希望大DMA家能正确认识FPGA,正确使用DMA技术,对于市场上各类伪装成花里胡哨设备的FPGA板卡它的本质是不会变的,不要上当受骗。 阅读详情

相关推荐

Linux运维踩坑实录:手把手教你修复LVM中PV显示[unknown]的诡异问题

本文详细解析了Linux运维中LVM物理卷(PV)显示[unknown]的故障现象及修复方法。通过分析问题根源、提供标准修复流程和特殊场景处理方案,帮助运维人员快速解决VG容量异常、PV状态丢失等问题,并分享预防措施与最佳实践,确保LVM存储系统的稳定运行。

weixin_26869081的博客 350

Spring整合ElasticJob 关闭Tomcat容器时内存泄漏

在完成定时任务的过程中,基本要求完成但是在项目停止的时候,Job 不能正常的去关闭,报出警告:  org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [***_Quart

u013611729的专栏 1276

STM32与FreeRTOS:基于TIM6的高精度系统时间获取实践

本文详细介绍了在STM32与FreeRTOS环境下,基于TIM6定时器实现高精度系统时间获取的实践方法。通过复用FreeRTOS的TIM6硬件资源,开发者可以高效获取毫秒级和微秒级系统时间,同时解决时间溢出和中断处理等关键问题。文章还提供了CubeMX配置技巧、代码实现及性能优化建议,适用于嵌入式系统开发中的精确时间管理需求。

weixin_29169505的博客 359

Elastic-Job分布式环境中有问题的解决方法

原文地址:http://dangdangdotcom.github.io/elastic-job/post/faq/ 4. 怀疑Elastic-Job-Lite在分布式环境中有问题,但无法重现又不能在线上环境调试,应该怎么做? 回答: 分布式问题非常难于调试和重现,为此Elastic-Job-Lite提供了dump命令。 如果您怀疑某些场景出现问题,可参照dump文

杨春建的博客 1794

BLDC六步换相驱动实战:从霍尔真值表到PWM调速的代码实现

本文详细解析了BLDC六步换相驱动原理,从霍尔真值表解读到PWM调速的代码实现,提供了基于STM32的实战方案。重点介绍了霍尔信号解码、换相状态机设计以及PWM动态调速策略,帮助开发者快速掌握无刷电机驱动技术。

weixin_28273593的博客 211

STM32F4驱动海康工业相机实战:从PWM信号到精准触发拍照(附完整代码)

本文详细介绍了如何使用STM32F4开发板驱动海康工业相机,实现PWM信号精准触发拍照的完整方案。从硬件连接到PWM信号生成,再到相机触发配置与延迟补偿,提供了实战经验和完整代码,帮助开发者解决工业相机硬件触发中的关键问题。

weixin_33716941的博客 698

Elastic-Job使用时的一些注意事项

1、官方提到“同一台服务器只能运行一个相同作业实例,因为作业运行时是按照ip注册和管理的”,那么:假如程序在同一台电脑上部署两个作业实例,结果会如何,会进行正常分片么?      该问题测试结果为:分片参数以shardingItemParameters=0=A,1=B,2=C,3=D,4=E,5=F,6=G,7=H,8=I,9=J为例:               a:同一机器,运

杨春建的博客 1万+

飞牛fnNAS搭建个人小账本

本文介绍了如何在飞牛NAS上部署ezBookkeeping个人记账应用。该开源工具支持多平台使用,具备双因素认证、多级分类等功能。文章详细讲解了Docker激活、镜像下载、容器部署等步骤,并展示了账户管理、交易记录等基础操作。同时指导用户通过ZeroTier实现远程访问,方便随时随地使用个人记账系统。该方案既保障了数据隐私,又提供了专业记账功能,适合对财务隐私敏感的用户。

dgnankai的专栏 783

elastic-job任务覆盖的异常

前情提要: 使用elastic-job-lite,job中对一个对象列表A进行批量计算。 操作:使用jmeter或直接调用接口,向对象列表A中增加一个对象,这时,先停止job,然后把对象列表修改完后重启job。 下面异常问题出现了,具体异常信息为: com.dangdang.ddframe.job.exception.JobSystemException: java.lang.NullPointerException at com.dangdang.ddframe.job.lite.intern

大头哥的哥 1093

Dify 系列教程 | 第 6 篇:工作流入门 -- 用可视化方式编排 AI 逻辑

Dify 工作流是一个基于有向无环图(DAG)的可视化 AI 逻辑编排系统。你可以把多个处理步骤(节点)用连线串联起来,数据从起点流向终点,每经过一个节点就被处理一次。用一个类比来理解:如果单次 Prompt 调用是"一道菜",那工作流就是"一道完整的生产线" – 原材料(输入)进入流水线,经过清洗(预处理)、切配(数据转换)、烹饪(AI 推理)、装盘(格式化输出)等工序,最终产出成品。创建一个工作流类型的应用(或高级聊天类型),就会进入工作流编辑器。编辑器基于ReactFlow构建(

weixin_43674738的博客 121

Jetson Nano之CSI摄像头操作方法

jetson端csi摄像头的应用方法

ZONGXP的博客 1万+

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

来源:https://knife.blog.youkuaiyun.com/article/details/124946774 今天给大家分享一种,Java内部类使用不当导致的内存泄露问题,最终导致内存溢出!希望能够帮助到大家! 简介 「说明」 本文介绍 Java 内部类持有外部类导致内存泄露的原因以及其解决方案。 「为什么内部类持有外部类会导致内存泄露?」 非静态内部类会持有外部类,如果有地方引用了这个非静态内部类,会导致外部类也被引用,垃圾回收时无法回收这个外部类(即使外部类已经没有其他地方在使用了)。 「解决方案」

Java技术栈,分享最主流的Java技术 702

汇川Easy系列PLC系统PID指令编程应用(增量型)

增量式PIDS7-1200/1500增量式PID(输出归一化、支持PWM输出)_西门子1200pid算法公式-优快云博客文章浏览阅读1k次。本文介绍了S7-1200/1500 PLC中增量式PID算法的应用,包括输出归一化和PWM输出。通过详细解析,阐述了PID输出如何限制在0.0-1.0之间,并且如何将PID输出与PWM占空比关联,适用于温度等控制场景。

RXXW_Dor的博客 1426

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

今天给大家分享一种,Java内部类使用不当导致的内存泄露问题,最终导致内存溢出!希望能够帮助到大家!1简介 说明本文介绍 Java 内部类持有外部类导致内存泄露的原因以及其解决方案。为什么内部类持有外部类会导致内存泄露?非静态内部类会持有外部类,如果有地方引用了这个非静态内部类,会导致外部类也被引用,垃圾回收时无法回收这个外部类(即使外部类已经没有其他地方在使用了)。解决方案不要让其他的地...

594

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

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

内部类改为静态的之后,它所引用的对象或属性也必须是静态的,所以静态内部类无法获得外部对象的引用,只能从 JVM 的 Method Area(方法区)获取到static类型的引用。内部类改为静态的之后,它所引用的对象或属性也必须是静态的,所以静态内部类无法获得外部对象的引用,只能从 JVM 的 Method Area(方法区)获取到 static 类型的引用。非静态内部类会持有外部类,如果有地方引用了这个非静态内部类,会导致外部类也被引用,垃圾回收时无法回收这个外部类(即使外部类已经没有其他地方在使用了)。

z_ssyy的博客 439

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: 接了个变态需求:生成 Excel + PDF 导出,用 Java 怎么实现?
下一篇: Lombok 同时使用 @Data 和 @Builder 的巨坑,千万别乱用!
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值