From:https://toutiao.io/shares/1013011/url
在Android(Java)开发中,基本都会遇到java.lang.OutOfMemoryError(本文简称OOM),这种错误解决起来相对于一般的Exception或者Error都要难一些,主要是由于错误产生的root cause不是很显而易见。由于没有办法能够直接拿到用户的内存dump文件,如果错误发生在线上的版本,分析起来就会更加困难。本文从一个具体的案例切入,介绍OOM分析的思路及相关工具的使用。
案例背景
在美团App 7.4~7.7版本期间,美食业务的OOM数量居高不下,远高于历史水平,主要都是DECODE本地的资源出错。
图中OOM数量为各版本发版后第一个月的统计量,包含新发版本及历史版本。对比了同时期其他业务的情况,也有类似OOM。由于美食业务的访问量占美团App的比重较大,因此,OOM的数量相对其他业务也多一些。
思路方案
在问题较为严重的7.6~7.7版本期间,团队对OOM频现的原因有过各种猜测。笔者怀疑过是否是业务上某些修改引起的,例如头图尺寸变大,或者是由页面模块加载方式引起的等等。但这些与OOM问题出现的时间并不吻合。其次也怀疑过是否由某些ROM的Bug导致,但此推断缺乏有力的证据支撑。因此,要找到OOM的root cause,根本途径还是找到谁占的内存最多,然后再根据具体case具体分析,为什么占了这么多。
采集用户手机内存信息
要分析内存的占用,需要内存的dump文件,但是dump文件一般都比较大,让用户配合上传dump文件不合适。所以希望能够运行时采集一些内存的特征然后随着crash日志上报上来。当用户发生OOM时,dump出用户的内存,然后基于com.squareup.haha:haha:2.0.3分析,得到一些关键数据(内存占用最多的实例及所占比例等)。但这个方案很快就被证明是不可行的。主要基于下面几个原因:
-
需要引入新的库。
-
dump和分析内存都很耗时,效率难以接受。
-
OOM时内存已经几乎耗尽,再加载内存dump文件并分析会导致二次OOM,得不偿失。
模拟复现OOM
采集用户手机内存信息的方案不可行,那么只能采取复现用户场景的方式。由于发生OOM时,用户操作路径的不确定性,无法精确复现线上的OOM,因此采取模拟复现的方式,最终发生OOM时的栈信息基本一致即可。为了能够尽量模拟用户发生OOM的场景,需要基本条件基本一致,即用户使用的手机的各种相关参数。
挖掘OOM特征
分析7.4以来的OOM,列出发生OOM的机器的特征,主要是内存和分辨率,适当考虑其它因素例如系统版本。
这些特征可以总结为:内存一般,分辨率偏高,OOM的堆栈log基本一致。其中,OPPO N1(T/W)上所发生的OOM比重较高,约为65%,因此选定这款机器作为复现OOM的机器。
关键数据(内存dump文件)
需要复现OOM然后获取内存dump。思路是采取内存压力测试,让问题暴露的快速且充分。具体方案为:
-
选取图片资源多且较为复杂的页面,比如美食的POI详情页。
-
加载30次该页面,为了增加OOM的几率,30个POI页面的ID是不同的。
OOM发生后,使用Android Studio自带的Android Monitor dump出HPROF文件,然后使用SDK中的hprof-conv(位于sdk_root/platform-tools)工具转换为标准的Java堆转储文件格式,这样可以使用MAT(Eclipse Memory Analyzer)继续分析。
切到histogram视图,按shadow heap降序排列。
选取byte数组,右击->list objects->with incoming references,降序排列可以看到有很多大小一致的byte[]实例。
如上图所示,这些byte[]都是系统的EdgeEffect的drawable所持有,drawable对应的bitmap占用的空间为1566 * 406 * 4 = 2543184,与byte数组的大小一致。
再看另外一个:
通过ImageView的ID(如图)及build目录下的R.txt反查可知该ImageView的ID名称,即可知其设置的背景图的大小为720 * 200(xhdpi),加载到内存并考虑density,size刚好是1080 * 300 * 4 = 1296000,与byte数组大小一致。
数据分析
为什么会出现这些大小一致的byte数组,或者说,为什么会创建多份EdgeEffect的drawable?查看EdgeEffect的源码(4.2.2)可知,其drawable成员也是通过Resources.getDrawable系统调用获取的。
不论是Resources.getDrawable还是TypedArray.getDrawable,最终都会调用Resources.loadDrawable。继续看Resources.loadDrawable的源码,发现的确是使用了缓存。对于同一个drawable资源,系统只会加载一次,之后都会从缓存去取。
既然drawable的加载机制并没有问题,那么drawable所在的缓存实例或者获取drawable的Resources实例是否是同一个呢?通过下面的代码,打印出每个Activity的Resources实例及Resources实例的drawable cache。
这也进一步解释了另外一个现象,即这些大小相同的数组的个数基本和启动Activity的数量成正比。
通过数据分析可知,这些drawable之所以存在多份,是因为其所在的Resources实例并不是同一个。进一步debug可知,Resources实例存在多个的原因是开启了标志位sCompatVectorFromResourcesEnabled。
虽然最终造成OOM突然增多的原因只是开启一个标志位,但是这也告诫大家阅读API文档的重要性,其实很多时候API的使用说明已经明确告知了使用的限制条件甚至风险。
7.8版本关闭了此标志,发版后第一个月的OOM数量(包含历史版本)为153,如下图。
其中新版本发生的OOM数量为22。
总结
对于线上出现的OOM,如何分析和解决可以大致分为三个步骤:
-
充分挖掘特征。在挖掘特征时,需要多方面考虑,此过程更多的是猜测怀疑,所以可能的方面都要考虑到,包括但不限于代码改动、机器特征、时间特征等,必要时还需要做一定的统计分析。
-
根据掌握的特征寻找稳定的复现的途径。一般需要做内存压力测试,这样比较容易达到OOM的临界值,只是简单的一些正常操作难以触发OOM。
-
获取可分析的数据(内存dump文件)。利用MAT分析dump文件,MAT可以方便的按照大小排序实例,可以查看某些实例到GC ROOT的路径。
相关推荐
本文将详细探讨一个线上出现的OOM问题,以及如何通过日志分析、使用Eclipse的Memory Analyzer Tool(MAT)以及最佳实践来定位和解决问题。 首先,我们看到的现象是Tomcat服务器在运行过程中出现了OOM错误,这通常...
基本上解决了OOM问题 如果 方便可以直接引用BitmapManager类到 项目中使用 解决blog 地址http://www.cnblogs.com/liongname/articles/2345087.html
在本项目中,"AndroidStudio————实战演练——仿美团外卖菜单"是一个专注于使用Android Studio开发的应用程序实战案例,目标是创建一个类似于美团外卖的菜单功能。这个项目涵盖了多个Android开发的关键知识点,...
在Android开发中,"OOM"(Out of Memory)是一个常见的问题,它指的是应用程序在...以上就是解决Android OOM的一些关键知识点,通过合理运用这些策略,开发者可以有效地减少和预防OOM问题,提升应用的性能和稳定性。
### Android内核驱动——内存管理:深入理解LowMemoryKiller机制 #### 一、LowMemoryKiller概述 在深入探讨LowMemoryKiller之前,我们先了解下它的背景和作用。LowMemoryKiller(低内存杀手)是Android内核中一种...
在Android开发过程中,经常会遇到一种常见的异常——OutOfMemoryError(简称OOM),这主要是因为Android为了确保设备性能与响应速度,在内存管理方面设定了严格的限制。对于每个应用程序进程,默认情况下只能使用...
OOM 9种常见原因及解决方案 以下是OOM 9种常见原因及解决方案的知识点: 1. Java Heap Space 错误 * 原因分析:请求创建一个超大对象、超出预期的访问量/数据量、过度使用终结器、内存泄漏 * 解决方案:通过 -Xmx...
综上所述,处理Android Bitmap OOM问题需要综合运用多种技术,包括调整图片大小、选择合适的编码格式、合理加载和释放Bitmap,以及利用库和缓存机制。在Android 2.0版本中关闭硬件加速是一个可行的解决方案,但应...
`oom_adj`(Out-of-Memory Adjuster)是Android用来管理进程优先级和内存分配的一个关键参数。较高的`oom_adj`值意味着该应用在内存清理过程中具有更高的保活优先级。以下是如何在Android 11源码中实现这一目标的...
- 使用Android Studio的内存分析工具,实时查看和分析内存使用情况,找出可能的内存泄漏。 综上所述,处理Android Bitmap OOM的关键在于合理控制Bitmap的内存占用,通过解码、缓存、回收和配置优化等方式进行有效...
在Android开发中,高效加载图片是一项至关重要的任务,因为不恰当的图片处理方式可能会导致内存溢出(Out Of Memory,简称OOM),严重影响应用性能和用户体验。本示例程序"android示例程序——高效加载图片"专门针对...
内存分析在Java应用程序的性能优化和故障排查中扮演着至关重要的角色。当应用程序出现Out of Memory (OOM)错误时,通常意味着系统无法...在日常开发和维护工作中,及时进行内存分析和优化,是避免和解决OOM问题的关键。
Android 内核驱动——内存管理 Android 内核驱动中,内存管理是一项非常重要的机制之一。Android 的内存管理机制是基于标准 Linux 内核的 Out of Memory (OOM) 机制修改而来的,称为 Low Memory Killer。Low ...
Android 加载大图片 OOM 异常解决方案 在 Android 开发中,加载大图片...通过手动干涉 Dalvik 的堆内存处理效率、手动指定 Android 堆大小、手动指定回收内存、指定 GC 和图片缩放,我们可以更好地解决 OOM 异常问题。
9. **内存分析工具**:Android Studio提供了内存分析工具,可以帮助开发者定位内存泄漏,查看内存使用情况,及时发现并解决OOM问题。 10. **生命周期管理**:确保在Activity或Fragment的生命周期方法中正确释放资源...
文件"关于Android oom的分析.docx"可能提供了更深入的案例分析和解决方案,建议查阅以获取更详细的信息。总的来说,理解Android内存管理机制并采取有效的内存优化策略,是防止和解决OOM问题的关键。
10. **监控内存使用**:使用Android Studio的内存分析工具,定期检查和调试内存泄漏,确保Bitmap被正确释放。 以上策略结合使用,可以有效地处理Android中的Bitmap OOM问题。在开发过程中,要持续关注性能和内存...
通过上述方式,我们可以有效地解决Android图片墙的OOM问题,提高应用的性能和稳定性。同时,开发者还应该时刻关注应用的内存使用情况,及时释放不再使用的资源,防止内存泄漏,确保应用的健康运行。