当前位置: 首页 > news >正文

Android - 看似内存泄漏,实则不是,记一次内存泄漏的案例分析

  APP中常常会存在内存泄漏的问题,一个简单的测试方法是,多次进入和退出同一页面(Activity),使用adb shell中的dumpsys meminfo com.android.settings | grep "Activities"来查看Activity的数量(以com.android.settings为例)。

  如果随着多次进入和退出,Activity的数量一致在增长,没有下降,那么便很大有可能是内存泄漏的问题。当然有可能是GC还没有回收的缘故,如果再显示地对调用GC回收(DDMS工具的Cause GC按钮),如果Acitivity的数量仍然没有降低,那么概率就更大了。需要从代码层面进一步分析。

  

  今天遇到的例子就是,通过上述方法,看似遇到了内存泄漏,其实不是

  关键点通过MAT工具和代码分析,未回收的对象被system_process进程引用,显示调用system_process GC即可解决问题,不属于内存泄漏。

  

  案例简介:在原生Android Open Source Project的Settings APP代码中,有一个Fragment类叫AccountPreferenceBase,运行在进程com.android.settings中,通过以上方法,发现这个类可能存在内存泄漏,于是在重现问题后,借助MAT工具,来分析,得到与此对象相关的引用链如下:

  

  

  由上图可知未被GC回收的AccountPreferenceBase与ContentResolver有关。通过代码分析,在AccountPreferenceBase中,相关的代码是如下,

  

  

  进一步分析,在onResume时,调用addStatusChangeListener时,内部会调用RemoteCallbackList的register方法(将callback的binder对象push进一个ArrayMap)。如果不再页面退出时,及时从ArrayMap中delete掉此binder对象,就会有内存泄漏的问题。但是我们在onPause中发现,其实已经调用了removeStatusChangeListener,其内部就会调用unregister方法,从ArrayMap中delete掉正确的binder对象。所以代码的写法没有问题。

   

  那是什么原因导致GC没有回收我们的Activity呢?

  原因就是,此ArrayMap是在system_process进程中,并非在com.android.settings的进程中,delete之后,如果执行一次GC(或者我们显示地对system_process调用一次GC),那么对象就会被回收。引用的settings进程中的Activity也会被回收释放。

  

  所以在此案例中,内存泄漏不存在。

  因此在遇到内存泄露的情况时,还是需要根据代码来具体分析,GC回收的时机不确定,可通过显示地调用GC来回收对象,排除某些内存泄露的可能。当然跨进程时,要调用正确进程的GC来回收。

转载于:https://www.cnblogs.com/KevinSong/p/5787934.html

相关文章:

  • Linux下创建软RAID5和RAID10实战
  • 【原创】遨游springmvc之HandlerMethodReturnValueHandler
  • css 样式表分类总结
  • Babel6.x 转换ES6
  • SharpGL学习笔记(五) 视口变换
  • win2012配置
  • shell运算(加、减、乘、除)
  • 配置 linux-bridge mechanism driver - 每天5分钟玩转 OpenStack(77)
  • Android listview的item设定高度
  • 解决使用Handler时Can't create handler inside thread that has not called Looper.prepare()
  • Spring注解解释(@Primary、@Qualifier)
  • storm-kafka(storm spout作为kafka的消费端)
  • js没有重载
  • 【索引】Oracle之不可见索引和虚拟索引的比对
  • 分区
  • Angular 响应式表单 基础例子
  • Consul Config 使用Git做版本控制的实现
  • ES2017异步函数现已正式可用
  • jquery ajax学习笔记
  • learning koa2.x
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • Twitter赢在开放,三年创造奇迹
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 闭包--闭包作用之保存(一)
  • 程序员该如何有效的找工作?
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 聊聊directory traversal attack
  • 聊聊sentinel的DegradeSlot
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 如何使用 JavaScript 解析 URL
  • 我从编程教室毕业
  • 一个项目push到多个远程Git仓库
  • 进程与线程(三)——进程/线程间通信
  • ​configparser --- 配置文件解析器​
  • ( 10 )MySQL中的外键
  • (12)目标检测_SSD基于pytorch搭建代码
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (windows2012共享文件夹和防火墙设置
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (九)c52学习之旅-定时器
  • (三)uboot源码分析
  • (转)http-server应用
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET企业级应用架构设计系列之开场白
  • /var/spool/postfix/maildrop 下有大量文件
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @GlobalLock注解作用与原理解析
  • [\u4e00-\u9fa5] //匹配中文字符
  • [2021]Zookeeper getAcl命令未授权访问漏洞概述与解决
  • [ai笔记9] openAI Sora技术文档引用文献汇总
  • [Android] 修改设备访问权限
  • [bzoj 3124][sdoi 2013 省选] 直径
  • [CLickhouse] 学习小计