专栏首页Android进阶Android高频面试专题 - 进阶篇(二)内存泄漏

Android高频面试专题 - 进阶篇(二)内存泄漏

内存泄漏往往面试会问到是否有解决过实际问题,这个如果答不好,也是很容易露馅的,面试时必须得把这艘火箭造好,才有机会进去拧螺丝。其他完整面试专题,请关注公众号查看。

1、Java虚拟机内存模型

完整内容参考Java内存模型

虚拟机栈:线程私有,随线程创建而创建。栈里面是一个一个“栈帧”,每个栈帧对应一次方法调用。栈帧中存放了局部变量表(基本数据类型变量和对象引用)、操作数栈、方法出口等信息。当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误。

本地方法栈:线程私有,这部分主要与虚拟机用到的Native方法相关,一般情况下,并不需要关心这部分的内容。

程序计数器:也叫PC寄存器,JVM支持多个线程同时运行,每个线程都有自己的程序计数器。倘若当前执行的是 JVM 的方法,则该寄存器中保存当前执行指令的地址;倘若执行的是native方法,则PC寄存器中为空。(PS:线程执行过程中并不都是一口气执行完,有可能在一个CPU时钟周期内没有执行完,由于时间片用完了,所以不得不暂停执行,当下一次获得CPU资源时,通过程序计数器就知道该从什么地方开始执行)

方法区:方法区存放类的信息(包括类的字节码,类的结构)、常量、静态变量等。字符串常量池就是在方法区中。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的是与Java堆区分开来。很多人都更愿意把方法区称为“永久代”(Permanent Generation)。从jdk1.7已经开始准备“去永久代”的规划,jdk1.7的HotSpot中,已经把原本放在方法区中的静态变量、字符串常量池等移到堆内存中。

:堆中存放的是数组(PS:数组也是对象)和对象。当申请不到空间时会抛出OutOfMemoryError。

2、内存泄漏原理

Android是基于Java的一门语言,其垃圾回收机制也是基于Jvm建立的,所以说Android的GC也是通过可达性分析算法来判定的。但是如果一个存活时间长的对象持有另一个存活时间短的对象就会导致存活时间短的对象在GC时被认定可达而不能被及时回收,而继续停留在堆内存中,也就是我们常说的内存泄漏。Android对每个App内存的使用有着严格的限制,大量的内存泄漏就可能导致OOM(内存溢出),也就是在new对象请求空间时,堆中没有剩余的内存分配所导致的。

3、Java引用类型

Java对引用的分类有 StrongReference(默认引用类型), SoftReference, WeakReference,PhatomReference 四种。

4、OOM是否可以try catch?

只有在一种情况下,这样做是可行的:

在try语句中声明了很大的对象,导致OOM,并且可以确认OOM是由try语句中的对象声明导致的,那么在catch语句中,可以释放掉这些对象,解决OOM的问题,继续执行剩余语句。但是这通常不是合适的做法。

5、finalize()方法

finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。

finalize方法至多由GC执行一次,即使在finalize()方法中复活对象,第二次GC如果对象仍不可达,那么还是会被回收。

6、Android查看内存/CPU占用信息

adb shell dumpsys meminfo pid

adb shell dumpsys cpuinfo|find "包名"

adb shell top

7、Android内存泄漏如何定位

使用Android Studio 自带的AndroidProfiler工具或MAT

使用Square产品的LeakCanary.

详情:https://www.jianshu.com/p/1972a6d1f0fc

8、LeakCanary原理

监测机制利用了Java的WeakReference和ReferenceQueue,通过将Activity(对象)包装到WeakReference中,被WeakReference包装过的Activity对象如果被回收,该WeakReference引用会被放到ReferenceQueue中,通过监测ReferenceQueue里面的内容,就能检查到Activity是否能够被回收。

详细原理:https://blog.csdn.net/tobetheender/article/details/53609563

9、常见内存泄漏的场景

  • 集合类泄漏
Vector v = new Vector(10); 
for (int i = 1; i < 100; i++) {
    Objecto = new Object(); 
    v.add(o); 
    o = null;
}
  • 单例造成的内存泄漏 由于单例的静态特性使得其生命周期跟应用的生命周期一样长,如果单例内部持有Activity/Fragment/View等的引用,会导致其无法被回收。
  • 匿名内部类/非静态内部类和异步线程 Java中,非静态内部类和匿名内部类默认会持有外部类的引用,比较容易引起内存泄漏的有Handler, AsyncTask使用匿名内部类形式。
  • 资源未关闭造成的内存泄漏 对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
  • 一些不良代码造成的内存压力 例如,只进行注册而没有反注册,构造 Adapter 时,没有使用缓存的 convertView。

10、避免内存泄漏的优化

直接就是针对上面提到的4点进行优化,集合资源add后不用及时remove;Handler使用静态内部类+弱引用,AsyncTask可以在onDestroy()内调用cancel方法;资源使用完及时进行close获取release;注册与反注册成对出现,Adapter进行convertView复用。

11、一个线程OOM后,其他线程是否还能正常工作?

美团18年三面题目

结合第1题,大家第一反应容易直观觉得是堆溢出,然后结合第1题堆是线程共享的,所以其他线程也都异常。实际上并非如此,当一个线程抛出OOM异常后,它所占据的内存资源会立即全部被释放掉,从而不会影响其他线程的运行。同理,栈溢出也是一样的。如果主线程抛异常退出了,子线程也还能运行,除非这些子线程是守护线程,那么会随着主线程异常结束而结束。

本文分享自微信公众号 - Android扫地僧(Android-Mas),作者:Android扫地僧

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 探索 Java 内存管理机制,面试别被问住了

    整理的目的是让我自己能对 Java 内存管理相关的知识的认识更全面一些,分享的目的是希望大家也能从这些知识中得到一些启发。

    Android扫地僧
  • 2019年面试实战总结,这些Android面试题你一定需要了解

    1:首先计算出 density,计算公式:当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) = densitydensity 的意思就是 1 d...

    Android扫地僧
  • Android高频面试专题 - 基础篇(三)Service

    ①Service生命周期内实例只会有一个,多次调用startService(),只有第一次会出发onCreate(),后面只会出发onStartCommand,...

    Android扫地僧
  • java基础面试题

    参考:http://blog.csdn.net/jackfrued/article/details/44921941 说未经允许不转载,我只好参考了。 1.面向...

    Ryan-Miao
  • Thread、ThreadPool、Task、Parallel、Async和Await基本用法、区别以及弊端

    ThreadPool是Thread的一个升级版,ThreadPool是从线程池中获取线程,如果线程池中又空闲的元素,则直接调用,如果没有才会创建,而Thread...

    Edison.Ma
  • JAVASE中的多线程小结,多生产多消费案例.

    因为线程任务已经被封装到Runnable接口中的run方法中,而这个run方法属于Runable接口的子类对象,所以要将这个子类对象作为参数传递给Thread类...

    帅的一麻皮
  • 再也不怕问我volatile关键字,你随便问!!!

    面试官问题:1.Java并发这块了解的怎么样?说说你对volatile关键字的理解?

    奋斗蒙
  • 类脑计算的前沿论文,看我们推荐的这7篇

    近年来随着传统人工智能算法逐步陷入瓶颈,人们期待与从脑科学中得到相应的启发来改进模型,进而从狭义人工智能走向通用人工智能。类脑智能作为人工智能重要的应用方向之一...

    马上科普尚尚
  • 使用 GraphQL 的 6 个月

    GraphQL 这个名词已经火了一段时间,但是一直没有体验过,无意中发现了一篇使用体验的文章,就想着翻译下分享给大家,如果翻译有问题的,还望批评指正。译文出自:...

    出其东门
  • MQTT学习笔记

    MQTT是一个C/S架构的发布/订阅模式的消息传输协议。它的设计思想是轻巧、开放、简单、规范,因此易于实现。这些特点使得它对很多场景来说都是很好的选择,包括受限...

    JKXQJ

扫码关注云+社区

领取腾讯云代金券