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

Android -- 每日一问:如何检测内存泄露,如何进行内存优化?

在这里插入图片描述

经典回答

Android 系统为每一个应用程序都设置了一个硬性的 Dalvik Heap Size 最大限制阈值,这个阈值在不同的设备上会因为 RAM 大小不同而各有差异。如果你的应用占用内存空间已经接近这个阈值,此时再尝试分配内存的话,很容易引起 OOM 。

在 Android Studio 上也可以通过 Memory Monitor 查看内存中 Dalvik Heap 的实时变化:
image.png
image.png

注意:GC 过于频繁容易出现内存抖动,这也是造成应用卡顿的常见原因。

也可以通过命行的方式查看:

adb shell dumpsys meminfo <package_name|pid> [-d]

具体的数值意义可以查看官网的说明:https://developer.android.com/studio/profile/investigate-ram.html

MAT 内存分析工具
详细的内存使用情况,可以通过 Android Studio 的 Android Monitor 界面,在 Memory 那栏有上几个小图标,点击有一个向下箭头的图标会自动生成并打开的 HPROF 视图。

不过用他来分析内存泄露还不是很智能,我们可以借助第三方工具,常见的工具就是 MAT 了(Memory Analyzer Tool),下载地址 http://eclipse.org/mat/downloads.php,这里我们需要下载独立版的 MAT(之前在使用Ecelipse开发Android应用时,我们常常会使用它的插件版本)。

注意:Android Monitor 生成的 HPROF 文件为 Dalvik 虚拟机格式的,需要转成 J2SE 虚拟机格式的,否则 MAT 工具中无法打开。转换的方式也很简单,Android Studio 自带了,直接在 “Captures”->“Heap Snapshot” 选中刚刚生成的".hprof" 文件,然后鼠标右键选择 “Export to standard .hprof” 可以在 MAT 上使用了。

MAT 的具体使用方式,网上很多,大家可以自己搜一下。这里就提一下用它怎么能快速查找到内存泄露的点,比如通过 “Dominator Tree”的"Path To GC Roots"的排除虚引用/弱引用/软引用等的引用链,因为被虚引用/弱引用/软引用的对象可以直接被GC给回收,我们要看的就是某个我们已经不需要使用的对象否还存在强引用链。比如,我们已退出一个Activity(onDestroy方法也被执行了),但在Path To GC Roots中却发现这个Activity对象还被有一个引用链,那么就可以确认这个Activity对像就产生了内存泄漏。一般来说,从它的引用链上也可以直观地看出是谁在引用它。

除了上面介绍了 MAT 检测内存泄露, 有一个叫LeakCanary工具大家也可以尝试一下。项目地址:https://github.com/square/leakcanaryLeakCanary会检测应用的内存回收情况,如果发现有垃圾对象没有被回收,就会去分析当前的内存快照,也就是上边 MAT 用到的 .hprof 文件,找到对象的引用链,并显示在页面上。这款插件的好处就是,可以在手机端直接查看内存泄露的地方,可以辅助我们检测内存泄露。

image.png

开发中如何避免内存泄漏

这点我比较喜欢问面试者,希望面试者能罗列出一些他自己遇到过的情况。通常来说,Activity 的泄漏是内存泄漏里面最严重的问题,它占用的内存多(它里面有N多资源的引用),影响比较明显。下面就示例两种错误的引用方式。

错误的单例模式

public class Singleton {
    private static Singleton instance;
    private Context mContext;

    private Singleton(Context context) {
        this.mContext = context;
    }

    public static Singleton getInstance(Context context) {
        if (instance == null) {
            instance = new Singleton(context);
        }
        return instance;
    }
}

这是一个非线程安全的单例模式,instance作为静态对象,其生命周期要长于普通的对象,其中也包含Activity,假如Activity A去getInstance获得instance对象,传入this,常驻内存的Singleton保存了你传入的Activity A对象,并一直持有,即使Activity被销毁掉,但因为它的引用还存在于一个Singleton中,就不可能被GC掉,这样就导致了内存泄漏。

View 持有 Activity 引用

public class MainActivity extends Activity {
    private static Drawable mDrawable;

    @Override
    protected void onCreate(Bundle saveInstanceState) {
        super.onCreate(saveInstanceState);
        setContentView(R.layout.activity_main);
        ImageView iv = new ImageView(this);
        mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
        iv.setImageDrawable(mDrawable);
    }
}

有一个静态的Drawable对象当ImageView设置这个Drawable时,ImageView保存了mDrawable的引用,而ImageView传入的this是MainActivity的mContext,因为被static修饰的mDrawable是常驻内存的,MainActivity是它的间接引用,MainActivity被销毁时,也不能被GC掉,所以造成内存泄漏。

其实避免 Activity 的泄漏的方式可以总结为:不要让生命周期长于 Activity 的对象持有到 Activity 的引用。

在开发中,我们也可以给一些初级的工程师相关的建议,如:

1. 注意单例模式和静态变量是否会持有对Context的引用;

2. 注意监听器的注销;(在Android程序里面存在很多需要register与unregister的监听器,我们需要确保在合适的时候及时unregister那些监听器。)

3. 不要在Thread或AsyncTask中的引用Activity;

你的朋友是不是也在准备面试呢?你可以把今天的题目分享给好友,或许你可以帮到他。

相关文章:

  • 10_缓存-2_二级缓存
  • 【FAQ】申请Health Kit权限的常见问题及解答
  • Servlet生命周期和线程安全
  • 【C++进阶】C++11新特性下篇(万字详解)
  • 一文读懂于Zebec生态中的潜在收益方式
  • 蓝桥杯有必要参赛吗?
  • 移植MQTT-C库(附源码)
  • 创建Series()对象--pandas
  • 【Linux】软件包管理器yum
  • 算法刷题打卡第49天:排序数组---计数排序
  • 【Linux】低级IO
  • 【Linux】shell命令以及运行原理
  • 【解决】Unity Player Log 自生成造成磁盘满占用率问题
  • 犀牛插件开发-基础核心-技术概览-总体架构-教程
  • 看2022年卡塔尔世界杯有感
  • bootstrap创建登录注册页面
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • IP路由与转发
  • Java 内存分配及垃圾回收机制初探
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • Mac转Windows的拯救指南
  • magento 货币换算
  • mysql 5.6 原生Online DDL解析
  • 大主子表关联的性能优化方法
  • 给初学者:JavaScript 中数组操作注意点
  • 来,膜拜下android roadmap,强大的执行力
  • 七牛云假注销小指南
  • 前端js -- this指向总结。
  • 前端路由实现-history
  • 算法-图和图算法
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • (+4)2.2UML建模图
  • (c语言)strcpy函数用法
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (算法二)滑动窗口
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)Linux下编译安装log4cxx
  • (转)我也是一只IT小小鸟
  • .Family_物联网
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .net实现客户区延伸至至非客户区
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • /bin、/sbin、/usr/bin、/usr/sbin
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • @html.ActionLink的几种参数格式
  • @Mapper作用
  • @Query中countQuery的介绍
  • @vue/cli脚手架
  • [bzoj1901]: Zju2112 Dynamic Rankings
  • [c++] C++多态(虚函数和虚继承)
  • [C++] 统计程序耗时
  • [CVPR2021]Birds of a Feather: Capturing Avian Shape Models from Images
  • [Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例
  • [IE编程] IE中对网页进行截图的编程接口
  • [IOI2007 D1T1]Miners 矿工配餐