Java内存泄漏系列--匿名内部类导致内存泄露--原因/解决方案
原文网址:Java内存泄漏系列--匿名内部类导致内存泄露--原因/解决方案_IT利刃出鞘的博客-CSDN博客
简介
说明
本文用示例介绍匿名内部类会导致内存泄漏的原因及其解决方案。
相关网址
普通内部类的内存泄露:Java内部类持有外部类导致内存泄露--原因/解决方案_IT利刃出鞘的博客-CSDN博客
为什么要持有外部类
Java 语言中,非静态内部类的主要作用有两个:
- 当匿名内部类只在外部类(主类)中使用时,匿名内部类可以让外部不知道它的存在,从而减少了代码的维护工作。
- 当匿名内部类持有外部类时,它就可以直接使用外部类中的变量了,这样可以很方便的完成调用,如下代码所示:
package org.example.a;import java.util.ArrayList;
import java.util.List;public class Demo {private static String name = "Tony";public static void main(String[] args) {List<String> list = new ArrayList<String>() {{add("a");add("b");add(name);}};System.out.println(list);}
}
实例:持有外部类
代码
package org.example.a;import java.util.ArrayList;
import java.util.List;class Test{public List<String> createList() {List<String> list = new ArrayList<String>() {{add("a");add("b");}};return list;}
}public class Demo {public static void main(String[] args) {System.out.println(new Test().createList());}
}
编译查看class
命令:javac Demo.java
结果:
Idea查看Test$1.class(可以发现:持有了一个外部类Test对象)
package org.example.a;import java.util.ArrayList;class Test$1 extends ArrayList<String> {Test$1(Test var1) {this.this$0 = var1;this.add("a");this.add("b");}
}
Idea查看Test.class
package org.example.a;import java.util.ArrayList;
import java.util.List;class Test {Test() {}public List<String> createList() {ArrayList var1 = new ArrayList<String>() {{this.add("a");this.add("b");}};return var1;}
}
Idea查看Demo.class
package org.example.a;public class Demo {public Demo() {}public static void main(String[] var0) {System.out.println((new Test()).createList());}
}
查看字节码
命令
javap -c Test$1.class
结果
Compiled from "Demo.java"
class org.example.a.Test$1 extends java.util.ArrayList<java.lang.String> {final org.example.a.Test this$0;org.example.a.Test$1(org.example.a.Test);Code:0: aload_01: aload_12: putfield #1 // Field this$0:Lorg/example/a/Test;5: aload_06: invokespecial #2 // Method java/util/ArrayList."<init>":()V9: aload_010: ldc #3 // String a12: invokevirtual #4 // Method add:(Ljava/lang/Object;)Z15: pop16: aload_017: ldc #5 // String b19: invokevirtual #4 // Method add:(Ljava/lang/Object;)Z22: pop23: return
}
分析
关键代码的在 putfield 这一行,此行表示有一个对 Test 的引用被存入到 this$0 中,也就是说这个匿名内部类持有了外部类的引用。
代码验证
package org.example.a;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;class Test{public List<String> createList() {List<String> list = new ArrayList<String>() {{add("a");add("b");}};return list;}
}public class Demo {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {List<String> list = new Test().createList();// 获取一个类的所有字段Field field = list.getClass().getDeclaredField("this$0");// 设置允许方法私有的 private 修饰的变量field.setAccessible(true);System.out.println(field.get(list).getClass());}
}
打个断点(注意:我这里是用Object模式(右键Variables里的this=> View as=> Object))
可见:它是持有外部类Test的对象的。
执行结果:
class org.example.a.Test
什么时候会内存泄露
非静态方法返回匿名内部类的引用可能导致内存泄露,例:
class Test{public List<String> createList() {List<String> list = new ArrayList<String>() {{add("a");add("b");}};return list;}
}
跟上边“普通内部类” 一样,若Test类里边有比较大的对象,而这些大对象根本没被用到,则会内存泄露。
不会内存泄漏的方案
方案1:不返回内部类对象引用
业务直接处理,不返回内部类对象引用
class Test{public void createList() {List<String> list = new ArrayList<String>() {{add("a");add("b");}};System.out.println(list);}
}
方案2:匿名内部类改为静态的
将匿名内部类改为静态的。此时,内部类不会持有外部类的对象的引用。
为什么这样就不会内存泄露了?
因为匿名内部类是静态的之后,它所引用的对象或属性也必须是静态的了,因此就可以直接从 JVM 的 Method Area(方法区)获取到引用而无需持久外部对象了。
代码
package org.example.a;import java.util.ArrayList;
import java.util.List;class Test{public static List<String> createList() {List<String> list = new ArrayList<String>() {{add("a");add("b");}};return list;}
}public class Demo {public static void main(String[] args) {System.out.println(Test.createList());}
}
执行结果
[a, b]
编译
命令:javac Demo.java
结果
Idea查看Test$1.class
package org.example.a;import java.util.ArrayList;final class Test$1 extends ArrayList<String> {Test$1() {this.add("a");this.add("b");}
}
Java内存泄漏系列--匿名内部类导致内存泄露--原因/解决方案相关推荐
- Java内存泄露系列--内部类持有外部类导致内存泄露--原因/解决方案
原文网址:Java内存泄露系列--内部类持有外部类导致内存泄露--原因/解决方案_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java内部类持有外部类导致内存泄露的原因以及其解决方案. 为什么内部 ...
- 会不会导致内存泄漏_可能会导致.NET内存泄露的8种行为
原文连接:https://michaelscodingspot.com/ways-to-cause-memory-leaks-in-dotnet/ 作者 Michael Shpilt.授权翻译,转载请 ...
- android 内存泄漏分析工具,Android内存泄漏终极解决篇(上)
一.概述 在Android的开发中,经常听到"内存泄漏"这个词."内存泄漏"就是一个对象已经不需要再使用了,但是因为其它的对象持有该对象的引用,导致它的内存不能 ...
- java 内存溢出和内存泄漏_JAVA中的内存溢出和内存泄漏有很大的区别
JAVA中的内存溢出和内存泄漏分别是什么,有什么联系和区别,我谈谈自己的理解. 内存泄漏(memory leak ):申请了内存不释放,比如100m的内存,分配了10m的内存一直不回收,那么可以用的内 ...
- java static内存泄漏_Java中的内存泄漏
内存泄漏是指不再使用的对象持续占有内存空间而得不到及时释放,从而造成内存空间的浪费称为内存泄漏.比如,长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是 ...
- java内存泄漏案例_寻找内存泄漏:一个案例研究
java内存泄漏案例 一周前,我被要求修复一个有内存泄漏问题的webapp. 考虑到过去两年左右的时间里我已经看到并修复了数百个泄漏,我想这有多难. 但是事实证明这是一个挑战. 12小时后,我发现该应 ...
- linux 内存泄漏 定位,一种内存泄露检查和定位的方法
一个系统后台服务进程,可能包括多个线程,在生成环境下要求系统程序能够稳定长时间稳定运行而不宕机.其中一个基本的前提就是需要保证系统程序不存在内存泄露.那么,该如何判读系统程序是否存在内存泄露呢?如果存 ...
- 电脑是否存在内存泄漏_如何避免内存泄露
如何避免内存泄露 关于内存泄露的原因有很多,最常见的有如下几种: 1 . 对于通过 new 等运算符申请到的内存空间在使用之后没有释放掉. 关于这个问题, 如果 是在过程程序中开辟的空间, 我们可以在 ...
- java内存泄漏怎么检测_JAVA内存泄漏原因和内存泄漏检测工具
JAVA内存泄漏原因和内存泄漏检测工具 摘要 虽然Java 虚拟机(JVM)及其垃圾收 集器(garbage collector,GC)负责管理大多数的内存任务,Java 软件程序中还是有可能出现内 ...
最新文章
- java模型给泛型_【一天一个基础系列】- java之泛型篇
- 笔记本电脑键盘切换_2019年最好的2500元以内的笔记本电脑
- onmounted vue3_Vue3.x 生命周期 和 Composition API 核心语法理解
- 网页视频之H5+Mse
- CODEVS 2102 石子归并 2
- 课程设计第一次实验总结
- js 中实现 汉字按拼音排序
- 计算机技术应用于测量,在测量绘图中计算机技术的应用分析
- go mysql 中间件_GitHub - wushilong/go-sharding: Mysql 分库分表中间件
- vscode vue代码格式化无效详细解决方案
- 皮皮虾技术三面,我的面试经验与总结分享
- 真正理解nodeJS,nodejs是什么,深入理解node
- 服务器的远程无法断开,远程桌面客户端断开连接且无法重新连接到同一会话
- python pip 连接超时,使用国内源下载
- 用python制作九宫格图片原来如此简单
- 画布渐变以及svg图形
- C语言:7-10 计算工资.2021-07-29
- Android中一个app启动另一个app|从浏览器打开app
- 机器视觉技术的发展动态
- 和用户一起做设计的时代
热门文章
- Python语言的基本介绍
- putty xming进入linux桌面,Xming PuTTY 远程登录linux桌面
- python有哪几种基本数据类型_Python最基本的数据类型以及对元组的介绍 Python 中列表和元组有哪些区别...
- 计算机学硕保博有必要读吗,学硕的直博或者保博是不是只能上本校的博士。如果这个学校没有博士点那是不是这个学校的学硕就不值得报了...
- BUUCTF:N种方法解决
- pandas常用操作集合
- 天津java培训班哪家好,干货整理
- 数据结构 - 串的模式匹配
- html新浪搜索框,JS+CSS实现仿新浪微博搜索框的方法
- 大数据存储引擎——Kudu