必定要注意 Android 内存泄漏问题

内存泄漏是引发Android应用崩溃常见的缘由,每一个Android开发人员都应该明白怎么避免发送。 经常使用的分析内存的工具备 Android ProfilerLeakCanaryjava

Android ProfilerLeakCanary

Android Profiler 是Android Studio提供的一个工具,用于实时观察应用的状况,包括:内存、CPU、网络等。android

LeakCanary 是一个第三方库,用于分析内存泄漏。官方地址:square.github.io/leakcanary/git

什么是内存泄漏

是什么致使了内存泄漏呢?当你的代码为一个对象分配了内存,可是却没有释放,就会形成内存泄漏,固然没有释放的缘由有不少种。github

不论是什么缘由,没有释放,是由于这个对象依然被别的对象引用,可是这些被引用的对象应该是要被销毁的。网络

Android 为每一个应用限制的最大内存使用量,当使用的内存超过最大值之后就会引起OOM,是程序奔溃,因此咱们要严格限制内存的使用。框架

为何咱们须要关注内存

系统回收内存的时候,你的程序会暂停,但一般这个过程是很是短暂的,通常用户感知不到。ide

可是有的时候你注意到你的程序变的缓慢和掉针,这是由于回收内存已经赶不上分配内存的速度了。工具

当内存泄漏发生的时候,内存会不断的增长,致使不断的触发gc,进而致使程序卡顿,甚至系统会强制杀死你的程序已便回收内存。字体

基于这些缘由,咱们必须的关注内存。优化

简单介绍下java内存模型

Java内存模型分为Jvm内存模型和Jmm内存模型。Jvm是java虚拟机内存模型,而Jmm内存模型是只为java程序服务。咱们一般讨论的Java内存模型,更多的是在讨论Jvm。

Jvm内存模型中按照线程是否独占,能够分为两部分。线程独占内存区有栈,本地方法栈和程序计数器,全部线程共享的有堆和方法区。

  • 也被称为Java虚拟机栈,它的生命周期与线程相同。每一个方法在执行的同时都会建立一个栈帧(Stack Frame)用于存储局部变量、操做数栈、动态连接、方法出口等信息。每一个方法从开始调用到执行完成对应入栈和出栈的过程。这个区域有两种异常状况:1,若是请求的深度大于虚拟机容许的深度,抛出StackOverflowError异常。2,若是扩展时没法申请到足够的内存,会抛出OutOfMemoryError异常。
  • 本地方法栈 和虚拟机栈相似,不过不是执行Java方法,而是执行本地方法。同Java虚拟机栈同样会抛出StackOverflowError和OutOfMemoryError异常。
  • 程序计数器 是一块较小的内存空间,用来保存当前程序执行的字节码位置。此内存是Java虚拟机中惟一快没有指定OutOfMemoryError的区域。只为执行Java方法服务。
  • 是Java中最大的一块内存,主要用于保存对象实例,几乎全部的线程对象实例都在这里分配内存。这也是垃圾回收器最主要的管理区域。内存不足时将会抛出OutOfMemoryError异常。
  • 方法区 用于存储类信息、常量、静态变量,即时编译器编译后的代码等数据。也叫非堆区。

Android 的内存有哪些

咱们可使用Android Sudio的 Memory Profiler 中查看App的内存状况。

内存计数中的类别以下:

  • Java:从 Java 或 Kotlin 代码分配的对象的内存。

  • Native:从 C 或 C++ 代码分配的对象的内存。 即便您的应用中不使用 C++,您也可能会看到此处使用的一些原生内存,由于 Android 框架使用原生内存表明您处理各类任务,如处理图像资源和其余图形时,即便您编写的代码采用 Java 或 Kotlin 语言。

  • Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。(请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)

  • Stack:您的应用中的原生堆栈和 Java 堆栈使用的内存。这一般与您的应用运行多少线程有关。

  • Code:您的应用用于处理代码和资源(如 dex 字节码、通过优化或编译的 dex 代码、.so 库和字体)的内存。

  • Others:您的应用使用的系统不肯定如何分类的内存。

  • Allocated:您的应用分配的 Java/Kotlin 对象数。此数字没有计入 C 或 C++ 中分配的对象。

    若是链接到搭载 Android 7.1 及更低版本的设备,只有在 Memory Profiler 链接到您运行的应用时,才开始此分配计数。所以,您开始分析以前分配的任何对象都不会被计入。不过,Android 8.0 及更高版本附带一个设备内置分析工具,该工具可跟踪全部分配,所以,在 Android 8.0 及更高版本上,此数字始终表示您的应用中待处理的 Java 对象总数。

Android中常见的内存泄漏

Android 中常见的内存泄漏来自Activity,Service,View等组件的不当使用。好比当一个Activity在被销毁后,还被别的对象持有的状况下,gc就无法回收这个activity,致使内存泄漏。 咱们来看一个内存泄漏的例子:

class MemoryLeakDemoActivity : AppCompatActivity() {

    companion object {
        private var activities: MutableList<Activity>? = mutableListOf()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_memory_leak_demo)

        // 这会形成内存泄漏
        activities?.add(this)
    }
}
复制代码

这段代码中,在onCreate方法咱们把当前activity对象加入到单例列表中,这样当这个activity被销毁后,却不能被gc回收,由于其对象还在被引用,这就形成了内存的泄漏。

总结

Android 对内存的要求的比较严格,每一个应用程序可以使用的内存都是有限的,不合理的使用内存会形成程序卡顿,甚至崩溃,因此每个开发者都应该要关注内存的使用状况。

参考

developer.android.com/studio/prof…

相关文章
相关标签/搜索