解决内存泄漏更加清楚的认识到Java匿名类与外部类的关系
1.事件起因
2.代码是怎么样让Volley 的缓存对象持有了mView对象呢?
public CCHttpRequest(final String url,final Map<String, String> params,final CCApiCallback callback) {mRequest = new HttpStringRequest(HttpGsonRequest.Method.POST, url) {@Overrideprotected Map<String, String> getParams() {return params;}@Overrideprotected void onResponse(String s) {
<pre name="code" class="java"> <span style="white-space:pre"> </span>if (null != callback) {callback.onResponse(data.toString(), hasServerTime, serverTime);}
} @Override protected void onErrorResponse(Exception e) { if (null != callback) { //系统错误返回-1 callback.onError(createErrorMessage(-1, e.getMessage())); } } }; } 被Volley缓存持有的对象是new HttpStringRequest 这个匿名类对象的实例,为什么方法中的参数final CCApiCallback callback这个参数会被新创建出来的匿名内部内持有呢?
3.一个简单的例子解释java匿名类与外部类的关系
书写一个简单的Hello.java文件,里面包括了一个匿名类与一个内部类Demo
public class Hello{private String mName="37785612";class Demo{public void show(){}}public void showDemo(final String s){new Demo(){public void show(){System.out.println("s="+s);System.out.println("name="+mName);}}.show();}
}
执行javac Hello.java编译完成后,会在同一目录下生成如下几个class文件,Hello.class,Hello$1.class,Hello$Demo.class。Hello.class就是我们源文件Hello的类文件,Hello$1.class是在showDemo()方法里面new Demo()那个匿名类的类文件,Hello$Demo.class是内部类Demo的类文件,我们这里主要分析Hello.class与Hello$1.class.
{
public Hello();Code:Stack=2, Locals=1, Args_size=10: aload_01: invokespecial #2; //Method java/lang/Object."<init>":()V4: aload_05: ldc #3; //String 377856127: putfield #1; //Field mName:Ljava/lang/String;10: returnLineNumberTable: line 1: 0line 2: 4line 3: 10public void showDemo(java.lang.String);Code:Stack=4, Locals=2, Args_size=20: new #4; //class Hello$13: dup4: aload_05: aload_16: invokespecial #5; //Method Hello$1."<init>":(LHello;Ljava/lang/String;)V9: invokevirtual #6; //Method Hello$1.show:()V12: returnLineNumberTable: line 8: 0line 14: 12static java.lang.String access$000(Hello);Code:Stack=1, Locals=1, Args_size=10: aload_01: getfield #1; //Field mName:Ljava/lang/String;4: areturnLineNumberTable: line 1: 0}
可以看到这里有一个方法access$000(Hello)是我们在源文件中没有出现的,而编译后会多了这个方法,它其实都是返回变量mName的值,后面会说到这个方法会被怎么用
继续执行命令javap -v Hello$1,汇编出来的部分代码如下
{
final java.lang.String val$s;final Hello this$0;Hello$1(Hello, java.lang.String);Code:Stack=2, Locals=3, Args_size=30: aload_01: aload_12: putfield #1; //Field this$0:LHello;5: aload_06: aload_27: putfield #2; //Field val$s:Ljava/lang/String;10: aload_011: aload_112: invokespecial #3; //Method Hello$Demo."<init>":(LHello;)V15: returnLineNumberTable: line 8: 0public void show();Code:Stack=3, Locals=1, Args_size=10: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;3: new #5; //class java/lang/StringBuilder6: dup7: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V10: ldc #7; //String s=12: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;15: aload_016: getfield #2; //Field val$s:Ljava/lang/String;19: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;22: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;25: invokevirtual #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V28: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;31: new #5; //class java/lang/StringBuilder34: dup35: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V38: ldc #11; //String name=40: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;43: aload_044: getfield #1; //Field this$0:LHello;47: invokestatic #12; //Method Hello.access$000:(LHello;)Ljava/lang/String;50: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;53: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;56: invokevirtual #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V59: returnLineNumberTable: line 10: 0line 11: 28line 12: 59}
我们可以看到这个匿名类多了两个成员变量final java.lang.String val$s与final Hello this$0;在看下这个匿名类的构造函数Hello$1(Hello, java.lang.String);刚好是对两个成员变量进行赋值。this$0指向了外部类对象的引用,val$s指向了方法showDemo(final String s)的参数s所指向内存的引用。在看看匿名类是怎么访问外部类的成员变量呢?看下这几行汇编代码:
43: aload_044: getfield #1; //Field this$0:LHello;47: invokestatic #12; //Method Hello.access$000:(LHello;)Ljava/lang/String;
43,调用匿名内的this对象,44,取得匿名类的this$0成员变量,就是(Hello对象) 47 调用Hello的静态方法static java.lang.String access$000(Hello);获取成员mName的值
4.找出真正原因
从上面关于匿名类与外部类的关系理清之后,我们能够发现,我代码中的callback持有了一个外部对象,层层回退,最下面一个callback对象持有了一个外部引用,而刚好这个外部对象又持有了一个mListener对象,而mListener内部类对象又持有了一个外部对象,这个外部对象又持有了mView,导致程序退出时由于Volley的缓存不释放,mView对象不会被垃圾回收,从而产生导致内存泄漏。
解决内存泄漏更加清楚的认识到Java匿名类与外部类的关系相关推荐
- Android 如何有效的解决内存泄漏的问题
前言:最近在研究Handler的知识,其中涉及到一个问题,如何避免Handler带来的内存溢出问题.在网上找了很多资料,有很多都是互相抄的,没有实际的作用. 本文的内存泄漏检测工具是:LeakCana ...
- Android 性能优化 - 彻底解决内存泄漏
起源 有趣的灵魂千奇百怪,内存泄漏的也是各式各样 我在15年写过一遍 文章 < android中常见的内存泄漏和解决办法>http://blog.csdn.net/wanghao20090 ...
- 内存(Display)、显示器(Monitor)和计算机(Computer)均属于一种产品(Product),其中计算机需要显示器和内存。请用Python语言简要实现这些类及它们之间的关系。
内存(Display).显示器(Monitor)和计算机(Computer)均属于一种产品(Product),其中计算机需要显示器和内存.请用Python语言简要实现这些类及它们之间的关系. clas ...
- jstat 内存泄漏_基于Java内存dump文件分析解决内存泄漏问题
概述 本文介绍一次解决现场java内存泄漏问题的经过,希望能提供后续遇到类似情况的读者一点思路. 生产环境发现的问题问题 生产环境运维人员反馈,服务器(windows系统)卡死,相关的服务都运行异常, ...
- 使用 Android Studio 检测内存泄漏与解决内存泄漏问题
本文在腾讯技术推文上 修改 发布. http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=BF ...
- android studio 解决内存泄漏
自从Google在2013年发布了Android Studio后,Android Studio凭借着自己良好的内存优化,酷炫的UI主题,强大的自动补全提示以及Gradle的编译支持正逐步取代Eclip ...
- 内存优化-使用tcmalloc分析解决内存泄漏和内存暴涨问题
其实我一直很想写关于tcmalloc的内存泄漏检测的文章,只是一直记不起来该如何下笔,有时项目太忙,在整理这方便的思考过少,另外遇到的问题也不是很多,直到最近用tcmalloc帮A项目排查一些很棘手的 ...
- # 学习记录1(C#-解决内存泄漏的几种方法)
这里写自定义目录标题 myImageCodecInfo = GetEncoderInfo("image/jpeg");myEncoder = Encoder.Quality;myE ...
- 解决内存泄漏导致的系统崩溃问题
问题描述:某机器煲机爱奇艺视频2.3h后,会出现爱奇艺崩溃,或者退出视频播放界面,或者提示爱奇艺已停止运行. 同类现象还有系统静置4-5h,会出现闪屏现象,屏幕亮灭亮灭显示. 问题Debug: 客户提 ...
最新文章
- 满足极高读写性能需求的Key-Value数据库
- 小程序分享朋友圈之填坑模式
- python列表list的基本性质
- python从多层循环嵌套中退出_python中退出多层循环的方法
- (JAVA) * 使用正则表达式,给字符串排序 * 使用数组排序
- POJ_3090.Visible Lattice Points
- Log4J 日志的异步类解读(lAsyncAppender)
- 奇怪的等待事件“enq: ss - contention”
- sql语言的一大类 DML 数据的操纵语言
- 解读mpvue官方文档的Class 与 Style 绑定及不支持语法
- 【优化预测】基于matlab灰狼算法优化BP神经网络预测【含Matlab源码 1729期】
- R语言学习笔记 | R语言的入门
- 学生社团管理系统(Java+Swing+mysql)(超简陋)
- 工行u盾显示316_详解工行U盾及使用方法和注意事项
- app抓包工具_安卓APP逆向入门分析——破解某APP登陆请求参数
- JAVA生成64,32位UUID密钥
- C++17新属性详解
- 广东未来科技:书写立体显示事业传奇的行业独角兽
- Unity -- 用EasyAR制作出AR红包
- 神经网络怎么学,怎么学神经网络
热门文章
- R语言 | 批量修改变量类型(比如:把所有字符型变量转化为因子型)
- Xero 系列之库存管理篇
- Java 面试的“完美圣经”,有了这些还愁面试吗?
- CentOS 8 安装golang
- 在小公司熬了两年后我终于如愿以偿进了阿里
- FP5207B:带软启动工作频率可调DC-DC升压IC
- 第四代计算机期间开始采用了,在第四代计算机期间内计算机的应用逐步进入到.docx...
- android手机通讯录没了,手机联系人不见了怎么恢复?手机通讯录误删如何恢复...
- 佳博Gainscha GP-3150TIN 打印机驱动
- iOS 苹果开发者中文网站学习