Android 非静态内部类导致的内存泄露(非static内部类)

miRNA测序数据生信分析——第一讲,总结概述 这里的miRNA测序指转录水平的测序。这里每一个数据库都可以在线访问,但是如果要本地使用,都需要进行数据库文件下载,整理。 阅读详情

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               
从.class文件分析非静态内部类和静态内部类的区别

我们看一个例子就明白了.

public class OuterClass {    public class NormallInnerClass {        public void call() {            fun();        }    }    public static class StaticInnerClass {        public void ask() {//            fun(); //compile error        }    }    public void fun() {    }}

在OuterClass中定义了2个内部类, 一个是普通的非静态内部类, 另一个是静态内部类.
用javap -c命令对.class文件反编译看下, 注意$前要加上\.
反编译OuterClass$NormallInnerClass.class :

wangxin@wangxin:~/src/browser_6.9.7_forcoopad$ javap -c ./out/production/browser/com/qihoo/browser/OuterClass\$NormallInnerClass.classCompiled from "OuterClass.java"public class com.qihoo.browser.OuterClass$NormallInnerClass {  final com.qihoo.browser.OuterClass this$0public com.qihoo.browser.OuterClass$NormallInnerClass(com.qihoo.browser.OuterClass);    Code:       0: aload_0              1: aload_1              2: putfield      #1                  // Field this$0:Lcom/qihoo/browser/OuterClass;       5: aload_0              6: invokespecial #2                  // Method java/lang/Object."<init>":()V       9: return          public void call();    Code:       0: aload_0              1: getfield      #1                  // Field this$0:Lcom/qihoo/browser/OuterClass;       4: invokevirtual #3                  // Method com/qihoo/browser/OuterClass.fun:()V       7: return        }

反编译OuterClass$StaticInnerClass.class :

wangxin@wangxin:~/src/browser_6.9.7_forcoopad$ javap -c ./out/production/browser/com/qihoo/browser/OuterClass\$StaticInnerClass.classCompiled from "OuterClass.java"public class com.qihoo.browser.OuterClass$StaticInnerClass {  public com.qihoo.browser.OuterClass$StaticInnerClass();    Code:       0: aload_0              1: invokespecial #1                  // Method java/lang/Object."<init>":()V       4: return          public void ask();    Code:       0: return        }

对比两个反编译的结果, 普通的非static内部类比static内部类多了一个field: final com.qihoo.browser.OuterClass this$0; 在默认的构造方法中, 用外部类的对象对这个filed赋值.
用intellij idea打开OuterClass$NormallInnerClass.class, 可以看到内部类调用外部类的方法就是通过这个filed实现的. 这也就是static 内部类无法调用外部类普通方法的原因,因为static内部类中没有这个field: final com.qihoo.browser.OuterClass this$0;

package com.qihoo.browser;import com.qihoo.browser.OuterClass;public class OuterClass$NormallInnerClass {    public OuterClass$NormallInnerClass(OuterClass var1) {        this.this$0 = var1;    }    public void call() {        this.this$0.fun();    }}
分析使用new Handler()导致的内存泄露

下面是常见的代码片段:

public class SampleActivity extends Activity {  private final Handler mLeakyHandler = new Handler() {    @Override    public void handleMessage(Message msg) {      // ...    }  }  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // 延时10分钟发送一个消息    mLeakyHandler.postDelayed(new Runnable() {      @Override      public void run() { }    }, 60 * 10 * 1000);    // 返回前一个Activity    finish();  }}

上面这段代码会导致内存泄露,它如何发生的?让我们确定问题的根源,先写下我们所知道的.
1、当一个Android应用程序第一次启动时,Android框架为应用程序的主线程创建一个Looper对象。一个Looper实现了一个简单的消息队列,在一个循环中处理Message对象。所有主要的应用程序框架事件(如Activity生命周期方法的调用,单击按钮,等等)都包含在Message对象中,它被添加到Looper的消息队列然后一个个被处理。主线程的Looper在应用程序的整个生命周期中都存在。
2、当一个Handler在主线程中被实例化,它就被关联到Looper的消息队列。每个被发送到消息队列的消息会持有一个Handler的引用,以便Android框架可以在Looper最终处理这个消息的时候,调用这个Message对应的Handler的handleMessage(Message)。

public final class Message implements Parcelable {    ...    Handler target;    ...}

3、在Java中,非静态的内部类和匿名类会隐式地持有一个他们外部类的引用, 也就是之前提到的final com.qihoo.browser.OuterClass this$0;。静态内部类则不会。
4、通过handler发送的runnable对象,会被进一步包装为message对象,放入消息队列.

所以, 对上面的例子来说, 当这个Activity被finished后,延时发送的消息会继续在主线程的消息队列中存活10分钟,直到他们被处理。这个message持有handler对象,这个handler对象又隐式持有着SampleActivity对象.直到消息被处理前,这个handler对象都不会被释放, 因此SampleActivity也不会被释放。注意,这个匿名Runnable类对象也一样。匿名类的非静态实例持有一个隐式的外部类引用,因此SampleActivity将被泄露。

为了解决这个问题,Handler的子类应该定义在一个新文件中或使用静态内部类。静态内部类不会隐式持有外部类的引用。所以不会导致它的Activity泄露。如果你需要在Handler内部调用外部Activity的方法,那么让Handler持有一个Activity的弱引用(WeakReference)是正确的解决方案。为了解决我们实例化匿名Runnable类可能导致的内存泄露,我们将用一个静态变量来引用他(因为匿名类的静态实例不会隐式持有它的外部类的引用)。

public class SampleActivity extends Activity {    /**    * 匿名类的静态实例不会隐式持有他们外部类的引用    */    private static final Runnable sRunnable = new Runnable() {            @Override            public void run() {            }        };    private final MyHandler mHandler = new MyHandler(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 延时10分钟发送一个消息.        mHandler.postDelayed(sRunnable, 60 * 10 * 1000);        // 返回前一个Activity        finish();    }    /**    * 静态内部类的实例不会隐式持有他们外部类的引用。    */    private static class MyHandler extends Handler {        private final WeakReference<SampleActivity> mActivity;        public MyHandler(SampleActivity activity) {            mActivity = new WeakReference<SampleActivity>(activity);        }        @Override        public void handleMessage(Message msg) {            SampleActivity activity = mActivity.get();            if (activity != null) {                // ...            }        }    }}
一句话, 都是java语法上隐式持有特性惹的祸,所以我们要对java语法有深入的理解, 不能只浮于表面.

refer:
http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
http://www.cnblogs.com/kissazi2/p/4121852.html



文/ahking17(简书作者)
原文链接:http://www.jianshu.com/p/6a362ea4dfd8
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
Anomalib实战指南:从零开始构建自定义异常检测数据集 本文提供了一份详细的Anomalib实战指南,指导用户从零开始构建自定义异常检测数据集。文章深入解析了数据准备的核心步骤、目录结构规范,并对比了PatchCore与FastFlow等关键模型的适用场景。通过清晰的代码示例,手把手演示了环境配置、模型训练与推理评估的全流程,旨在帮助开发者快速掌握这一工业视觉异常检测利器,有效解决实际生产中的缺陷识别难题。 阅读详情

相关推荐

IgH EtherCAT 从入门到精通:第 29 章 实战:EoE 远程维护通道搭建

摘要:本章详细介绍了基于EoE(Ethernet over EtherCAT)协议的远程维护通道搭建方案。主要内容包括:1)网络架构设计,采用管理网络与EoE子网隔离的方案;2)从站EoE支持确认与IP地址配置,提供API和命令行两种方式;3)路由/交换两种部署模式,重点推荐路由模式并给出自动化配置脚本;4)SSH远程访问配置,包括直接连接和跳板访问两种方式;5)安全加固措施,如防火墙规则、SSH密钥认证等;6)故障恢复机制与性能注意事项。该方案实现了通过EtherCAT网络对从站设备的远程SSH访问、文件

从事嵌入式linux android驱动开发,拥有全栈能力 316

Android内存泄漏详解和总结

对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我们可以借助LeakCanary工具来检测应用程序是否存在内存泄漏,LeakCanary则是由Square开源的一款轻量第三方内存泄漏检测工具,当它检测到程序中有内存泄漏的产生时,它将以最直观的方式告诉我们该内存泄漏是由谁产生的和该内存泄漏导致谁泄漏了而不能回收,供我们复查。...

UrasakiNakajima的博客 1829

基于Simulink进行光伏逆变器效率分析的仿真建模

特点能量转换:将光伏电池板产生的直流电转换为交流电。效率评估:分析逆变器在不同负载条件和环境条件下的效率。动态特性:考虑温度、光照强度等外部因素对逆变器效率的影响。挑战精确建模:准确地模拟光伏电池板、逆变器及其交互的动力学过程。多因素考量:需要同时考虑输入电压、电流、温度、光照强度等多种因素对逆变器效率的影响。集成度:需要与其他系统(如最大功率点跟踪MPPT算法、电网连接等)无缝集成,以实现全面的系统分析。首先明确要模拟的任务内容。输入条件(如光照强度、温度等)。

amy_mhd的博客 124

Android技巧】--防崩溃处理

简单介绍:    Android开发过程中,因为各种原因导致app崩溃的现象层出不穷,异常奔溃带来的用户体验及其差劲,尤其当一个小小的功能页面的问题导致app整体奔溃带来的操作感受极差,防止app奔溃,虽然不能从根本解决用户体验的基本问题,但可以在此基础上处理,并带来更好地错误交互处理方法。    程序中,可以捕捉到的异常,通常使用try...catch..finally来解决,但还存在一些我们没...

shankezh的博客 4777

Android Architecture Components(三)ViewModel分析

ViewModel简介 与上一篇文章相同,先官方文档翻译,再源码分析~ 我们先看一下官方文档的介绍: The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configu...

Dengzm94 560

Android中常见的内存泄露及解决方法(持续更新)

内存泄露的原因 内存泄露是指不在需要的对象仍然被引用不能被GC回收释放,这句话你可能看到过不止一遍了,下面我们来深入研究一下这句话。 首先了解一下两个名词: GC: 垃圾回收器,会自动回收不在被引用的内存数据 GC Roots:不能被回收的对象(这里的解释不是很好,往下看就明白了) 下面我们来看一张图: GC Roots持有的对象都不能被垃圾回收器回收,所以这里的Object D...

一只特立独行的猪 1293

Android小知识-静态内部类导致内存泄露

本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众 静态内部类(包括匿名内部类)默认就会持有外部类的引用,当静态内部类对象的生命周期比外部类对象的生命周期长时,就会导致内存泄露静态内部类导致内存泄露Android开发中有一种典型的场景就是使用Handler,很...

weixin_33881753的博客 365

android编译静态内部类,android non-static内部类导致内存泄露

从.class文件分析静态内部类静态内部类的区别我们看一个例子就明白了.public class OuterClass {public class NormallInnerClass {public void call() {fun();}}public static class StaticInnerClass {public void ask() {// fun();...

weixin_36139228的博客 183

Android内存优化场景

Android内存优化场景小结

Crazy程序猿 1053

Android 性能优化:手把手带你全面了解内存泄露,安卓高级面试题及答案

/ 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合Listi < 10;// 虽释放了集合元素引用的本身:o=null)// 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象由于1个集合中有许多元素,故最简单的方法 = 清空集合对象 & 设置为null// 释放objectList。

2401_84149802的博客 699

android handler资源占用,Android性能优化:关于 内存泄露 的知识都在这里了!(文不如图,图不如表)...

// 释放objectListobjectList.clear();objectList=null;5.2 Static 关键字修饰的成员变量储备知识 被 Static 关键字修饰的成员变量的生命周期 = 应用程序的生命周期泄露原因 若使被 Static 关键字修饰的成员变量 引用耗费资源过多的实例(如Context),则容易出现该成员变量的生命周期 > 引用实例生命周期的情况,当引用实例需...

weixin_35832025的博客 250

android reference,Android WeakReference

探讨一下为什么Android Studio会提示handler类要写成static的。下面这张图是匿名内部类创建一个对象(本质上是继承了Handler然后覆写了它的方法)。定义一个静态内部类然后再new也会有这个提示。(为什么直接new 一个Handler类的对象就不会提示,因为不会持有外部类的引用)。image.png更典型的场景:image.png问题原因image.pngActivity在...

weixin_26831583的博客 272

边实验边分析 - 静态内部类引发的内存泄漏问题

邊實驗邊分析 - 使用AIDL引起的内存泄露問題

卡卡尔的专栏 861

Android Jetpack ViewModel由浅入深

附上官网链接:https://developer.android.google.cn/topic/libraries/architecture/viewmodel ViewModel简介 该ViewModel类被设计用来存储和管理UI界面相关的数据生命周期中的意识的方式。ViewModel类允许生存数据配置更改,如屏幕旋转。 存在的意义 (解决痛点) 1. 数据的持久化 eg: 当系统销毁或重新...

loveblueldr的博客 357

Android常见内存泄漏

1、静态内部类默认持有外部类的引用会导致内存泄漏 静态内部类静态内部类之间存在一个最大的区别,就是静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。 代码: public class Outer { private void outerDo() {} class Inter { private void innerDo() { // 内部类可以直接访问外部类成

qq_40959750的博客 735

android——怎么写内部类才能防止内存泄漏以及怎么查看内存泄漏

静态内部类是指在一个类的内部定义另一个静态类,这个静态类就成为了外部类的成员之一。在Java中,要防止静态内部类内存泄漏,需要注意以下几点:静态内部类必须保存对外部类实例的引用,因此要避免外部类实例和内部类实例的相互引用,否则会导致内存泄漏。要避免内部类持有外部类实例的引用,可以使用弱引用或者静态内部类的方式。如果使用弱引用,要注意判断弱引用是否为空,否则会产生空指针异常。

wy313622821的博客 1260

Android中高级面试题(三):静态内部类是什么?和静态内部类的区别是什么?

可以看到,普通内部类构造方法中实际上会隐式的传递外部类实例对象给内部类。在内部类中使用外部类的属性:i。实际上是通过外部类的实例对象:var1获取的。静态内部类中不再隐式的持有外部类的实例对象。内部静态类不需要有指向外部类的引用。但静态内部类需要持有对外部类的引用。当内部类static声明,那么在内部类中就无法直接使用外部类的属性。在定义内部类时,如果内部类static声明,则该内部类静态内部类。此时无法使用外部类的普通成员属性:i。的实例对象,静态内部类也无法脱离外部类实体被创建。

Android 开发架构 202

内存泄漏那些事

最近在做内存优化方面的需求,总结出了一些常见的问题,之后会一直更新并记录,希望读者也可以进行补充,在评论区可进行补充~~ 定义 定义:程序分配的堆内存中由于某种原因造成无法及时释放某些对象,造成内存泄漏内存泄漏多了就容易造成内存溢出 哪些情况会出现内存泄漏 1.集合 造成内存泄漏的原因:集合释放掉了,但时集合中还持有某些对象的引用,造成这些引用不能被及时回收 解决方法:持有的对象引用和自身都需要释放资源 2. 匿名内部类|静态内部类 造成内存泄漏的原因:默认情况下静态内部类持有外部类对象的引用,当程

北洋的博客 1589

tensorflow-2.17.0-cp312-cp312-win_amd64.whl

tensorflow-2.17.0-cp312-cp312-win_amd64.whl

基于Springboot+mysql的校园在线拍卖系统设计与实现(源码+部署说明+视频演示).zip

资源名字:基于Springboot+mysql的校园在线拍卖系统设计与实现(源码+部署说明+视频演示).zip资源内容:项目全套源码+完整文档 源码说明: 全部项目源码都是经过测试校正后百分百成功运行。基于Spring Boot和MySQL的校园在线拍卖系统是一个用于校园内物品拍卖的平台,具有以下主要特点:技术栈:该系统采用了Java技术栈中的Spring Boot框架,配合MySQL数据库,具备良好的技术稳定性和可靠性。用户管理功能:系统支持用户注册、登录、个人信息管理等功能,用户可以创建个人账户并管理自己的拍卖物品。物品发布与浏览功能:用户可以发布待拍卖物品的信息,包括物品描述、起拍价、拍卖时间等,其他用户可以浏览和搜索感兴趣的物品。竞拍功能:用户可以参与物品的竞拍,提交出价并跟踪拍卖进展,系统会自动记录和展示当前最高出价者。拍卖管理功能:系统提供拍卖物品的管理功能,包括发布、编辑、删除物品信息,管理员可以对拍卖过程进行监督和管理。数据管理与统计分析:系统合理设计数据库结构,包括用户信息、物品信息、竞拍记录等表,支持数据的管理和统计分析,为用户和管理员提供有价值的数据支持。界面友好:系统拥有直观、美观的用户界面和良好的交互体验,用户可以轻松浏览和参与拍卖活动,提高使用的便捷性和舒适度。安全性和隐私保护:系统采用安全措施,保护用户个人信息的安全和隐私,确保数据的保密性和完整性。总之,基于Spring Boot和MySQL的校园在线拍卖系统具有技术稳定性高、用户管理、物品发布与浏览、竞拍功能、拍卖管理、数据管理与统计分析、界面友好、安全性保护等特点,为校园内物品拍卖提供了方便、可靠和安全的在线平台。

上一篇: bash useradd command not found如何解决 (by 星空武哥)
下一篇: AndroidStudio生成自定义的混淆jar包(同时将assets目录打入jar包)(二)(by 星空武哥)
这个1500的
博客等级 码龄8年 10粉丝 90原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值