zoukankan      html  css  js  c++  java
  • 在Android中解决内存溢出 – OutOfMemoryError

    原文链接:http://riggaroo.co.za/fixing-memory-leaks-in-android-outofmemoryerror/

    注:本文在原文基础上在如何判断内存是否泄露方面进行了补充

    安卓开发中经常出现内存溢出的情况,没有防备的开发者可能一天会不经意间写好几个内存溢出的漏洞。你可能不会发现这些漏洞,甚至都不知道它们存在,直到你看到这种异常:

    java.lang.OutOfMemoryError: Failed to allocate a 4308492 byte allocation with 467872 free bytes and 456KB until OOM
    at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988)
    at android.content.res.Resources.loadDrawableForCookie(Resources.java:2580)
    at android.content.res.Resources.loadDrawable(Resources.java:2487)
    at android.content.res.Resources.getDrawable(Resources.java:814)
    at android.content.res.Resources.getDrawable(Resources.java:767)
    at com.nostra13.universalimageloader.core.DisplayImageOptions.getImageOnLoading(DisplayImageOptions.java:134)
    

    这是啥意思呢?难道我的Bitmap太大了?

    这种异常信息可能会让你产生误解。当你看到OutOfMemoryError的时候,十有八九是内存泄露。我第一次看到这个就以为我的Bitmap太大了,唉当时的我太年轻了。

    什么是内存泄露?

    内存泄露指程序中没有正确的释放用完的内存空间,导致运行异常或错误

    Android中内存泄露是如何发生的?

    事实上Android中内存泄露很容易发生。最大的问题就是Context对象。

    每 一个App都有一个全局的Application Context对象,可以通过getApplicationContext()方法获得。每一个Activity都是Context的子类,会存储有关当 前Activity的信息。很多情况下,内存泄露与Activity泄露有关。比如有的开发者会将Context对象在各个线程里传来传去,写一些静态的 TextView,让它们持有Activity的引用,这就是一个典型的错误。

    判断是否有内存泄露

    Memory Monitor

    1. 将设备或模拟器与Android Studio连接。

    2. 在Android Studio中运行程序。

    3. 在 屏幕下方点击Android标签,再点击Memory标签,选择设备与要监控的应用。一旦Memory Monitor开始监控设备,就会出现蓝色的图表显示内存使用情况。深蓝色部分为当前应用正在使用的内存,浅蓝色(深蓝色上面那一块)为可以使用、未被分 配的内存空间。

      演示图片

    4. 点击垃圾车图标(上图右侧那个小图标)可以触发GC(内存回收)。

    有内存溢出漏洞的应用在不断操作并触发GC后的图表不断上升的:

    有内存泄露

    内存泄露被解决后的应用不断操作并不断触发GC后图表波动但维持稳定:

    无内存泄露

    DDMS

    打 开DDMS界面,在左侧面板中选择要观察的进程,点击左上角的Update Heap按钮(红圈圈出的圆柱体按钮),再点击右侧面板中的Heap标签,然后不断操作并持续点击Cause GC按钮,观察表中data object的Total Size的数值变化。如果持续增高而不下降,那就很可能是有内存泄露发生了。

    DDMS

    有内存泄露时,应用不会重新得到用过的内存空间,当用到300MB的时候,OutOfMemoryError就发生了。从修复了内存泄露的应用的图表可以看出,应用可以回收一些内存,并处在长期稳定状态。

    如何避免内存泄露?

    • 不要将Context对象传给activity与fragment以外的对象。

    • 永远不要将Context和View存储在静态变量中。

        private static TextView textView;//不要这么干
        private static Context context;//不要这么干
      
    • 在onPause()/onDestroy()方法中解除监听器,包括在Android自己的Listener,Location Service或Display Manager Service以及自己写的Listener。

    • 不要在后台线程与AsyncTask中存储activity的强引用。不然当Activity被关闭后,由于AsyncTask仍在执行且持有Activity的强引用,导致Activity无法被回收。

    • 使用Application Context而不是Activity的Context

    • 尽量不要用非静态内部类,因为它会持有外部类的引用。在非静态内部类中存储Activity或View的引用会导致内存泄露。如需存储就使用WeakReference。

    如何解决内存泄露?

    解决内存泄露需要大量的错误积累与练习。内存泄露可能会很难追踪,但借助一些工具可以帮助你识别可能的漏洞。这里我们使用MAT进行内存泄露的检测。

    1. 打开Android Studio,点击下方的Android Monitor标签。

    2. 运行应用,并选择应用来监控。

    3. 反复进行某个可能存在内存泄露的操作,比如返回打开关闭某个Activity。

    4. 在抛出OutOfMemoryException之前点击Android Monitor中的Memory标签。此时图表开始绘制,过一会点击GC图标。(刚才说的那个红色垃圾车图标)

      hprof1

    5. 点击垃圾车下面那个有绿色箭头的图标”Dump Java Heap”,并等待几秒。然后会生成一个.hprof文件,这个文件就是用来分析内存使用的。

    6. 下载MAT

    7. 使用sdk中platform-tools路径下的hprof-conv文件将刚才生成的.hprof文件转码成MAT可以解析的文件。

       ./hprof-conv path/file.hprof exitPath/heap-converted.hprof
      
    8. 使用MAT打开转码后的文件。选择”Leak Suspects Report”然后点击”Finish”。

      hprof2

    9. 点击界面上方三条竖杠的图标。而后你会看到占用内存的对象的列表。

      hprof3

    10. 这个列表可能难以理解,你可以输入类名来过滤结果。我建议在输入框中输入package name,如下:

      hprof4

    11. 现 在我们可以看到VideoDetailActivity的9个实例,这显然不对,因为我们只应该有一个。我们可以右键单击这一条目并选择”Merge Paths to Shortest GC Root”并点击“exclude all phantom/weak/soft etc.references”来看是什么持有VideoDetailActivity的引用。

      hprof5

      而后持有引用的的线程就会显示出来。而后你就可以深入观察什么持有了Activity的引用。

    12. 通过下面的信息我们可以看到有一个DisplayListener被注册了但从未解除。

      hprof6

    所以这个漏洞就找到了,只需要解除监听器就可以了。

    不是所有的内存泄露漏洞都这么容易找到。希望这篇文章可以帮你避免内存泄露并在内存泄露发生时找到漏洞。

    推荐:

    Android 多种方式正确的加载图像,有效避免oom

  • 相关阅读:
    Ftp、Ftps与Sftp之间的区别
    Previous Workflow Versions in Nintex Workflow
    Span<T>
    .NET Core 2.0及.NET Standard 2.0 Description
    Announcing Windows Template Studio in UWP
    安装.Net Standard 2.0, Impressive
    SQL 给视图赋权限
    Visual Studio for Mac中的ASP.NET Core
    How the Microsoft Bot Framework Changed Where My Friends and I Eat: Part 1
    用于Azure功能的Visual Studio 2017工具
  • 原文地址:https://www.cnblogs.com/android-blogs/p/5816988.html
Copyright © 2011-2022 走看看