4年前 (2020-12-14)  jvm |   抢沙发  1217 
文章评分 0 次,平均分 0.0

Android中的内存泄漏很容易造成。毫无防备的开发人员可能每天都在不知不觉中泄露一些内存。你可能还没有注意到它们,甚至还不知道它们的存在。直到你看到这样的例外…

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对于Android系统来说太大了?

不幸的是,看到这种堆栈跟踪可能有点欺骗。当您收到OutOfMemoryError时,通常意味着10次中有9次内存泄漏。我对这个堆栈跟踪的第一印象让我很困惑,认为我的位图太大了……天哪,我错了。

什么是内存泄漏?

程序中释放被丢弃的内存的一种失败,导致性能下降或失败。

安卓系统是如何导致内存泄漏的?

Android中的内存泄漏实际上很容易造成,这可能是问题的一部分。最大的问题是Android的背景。

每个应用程序都有一个全局应用程序上下文(getApplicationContext())。每个活动都是Context的一个子类,它存储与当前活动相关的信息。通常情况下,您的内存泄漏将与泄漏的活动相关。

谦逊的开发人员会将这个上下文对象传递给需要它的线程。制作一些静态文本视图来保存对活动的引用。你知道,是什么让它成功的?有意讽刺,不要在家里尝试那些东西

Android内存泄露定位

需要注意的一个重要警告信号是应用程序中内存使用量的不断增加,如Androids memory Monitor所示:

Android内存泄露定位

Android内存监视器运行的应用程序存在内存泄漏

Android内存泄露定位

安卓内存监视器修复内存泄漏后

正如你所看到的,第一张图,应用程序永远无法真正恢复使用的一些内存。在OutOfMemoryError发生之前,它一度占用了大约300MB的空间。第二张图显示,该应用程序能够进行垃圾收集,重新获得一些内存,并在内存使用方面保持相当一致。

如何避免内存泄漏?

  • 避免传递比活动或片段更远的上下文对象
  • 永远不要在静态变量中创建/存储上下文或视图。这是内存泄漏的第一个迹象。
private static TextView textView; //DO NOT DO THIS
private static Context context; //DO NOT DO THIS
  • 总是在onPause()/onDestroy()方法中注销侦听器。这包括Android侦听器、位置服务或显示管理器服务以及您自己的自定义侦听器。
  • 不要在异步任务或后台线程中存储对活动的强引用。您的活动可能会关闭,但你的AsyncTask将继续执行并保留活动的引用。
  • 如果可以,请使用上下文应用程序(getApplicationContext())而不是活动中的上下文。
  • 如果可以避免的话,尽量不要使用非静态内部类。将对活动或视图之类的引用存储在其中可能会导致内存泄漏。如果需要存储对它们的引用,请使用WeakReference

内存溢出怎么解决

修复内存泄漏需要一点实践和大量的尝试和错误。内存泄漏很难追踪。幸运的是,有一些工具可以帮助您识别可能的泄漏。

1. 打开Android Studio,打开Android监视器选项卡。

2. 运行应用程序,并从可用应用程序列表中选择它。

3. 在你的应用程序中做一些能让你达到类似目的的动作。对我来说,就是选择一个新的视频,然后播放大约50次。

4. 这里的诀窍是在OutOfMemoryException之前捕获应用程序。

5. 点击Android监视器中的memory标签。

Android内存泄露定位

6. 你应该看到一个很好的图表开始绘制。准备就绪后,单击“启动GC”。(小红垃圾车)

7. 单击“dumpjavaheap”并等待几秒钟。(卡车下方带有绿色箭头的图标)。这将生成一个.hprof文件,可用于分析内存使用情况。

8. 不幸的是,androidstudio hprof文件查看器没有Eclipse内存分析器所拥有的所有工具。所以你需要安装MAT。

9. 运行以下命令将Android中的.hprof文件转换为MAT可以理解的文件。(hprof conv工具位于sdk的platform tools文件夹中)

./hprof-conv path/file.hprof exitPath/heap-converted.hprof

10. 转换后,在MAT中打开文件。选择“Leak Suspects Report”泄漏嫌疑报告,然后单击“完成”。

Android内存泄露定位

11. 单击顶部的3个蓝色条 Create a histogram from an arbitrary set of objects“从任意对象集创建直方图”。然后您将看到占用内存的对象列表。

Android内存泄露定位

12. 看到这个对象列表可能有点混乱。您可以按类名筛选对象,因此我建议在类名过滤器中键入包名。

Android内存泄露定位

13. 现在我们可以看到有9个VideoDetailActivity实例,这显然是不对的,因为我们应该只有一个。要找到对VideoDetailActivity的引用,请右键单击该项并选择“Merge Paths To Shortest GC Root”,然后单击“排除所有虚/弱/软等引用”。

Android内存泄露定位

将显示保存引用的线程。然后,您将能够深入了解活动的具体引用内容。

14. 从下面的信息可以清楚地看出,有一个displaylister被注册了,但从未被注销过。

Android内存泄露定位

因此,通过在已注册的显示侦听器上调用unregister来解决内存泄漏问题。

DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
displayManager.unregisterDisplayListener(listener);

希望你能从中找到更多的漏洞,希望你能从中找到更多的漏洞。有很多其他的工具可以用来发现内存泄漏,请在这里查看。
Android内存泄露定位

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1017.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册