




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】Android进阶性能调优;不可思议的OOM
本文发现了一类OOM(OutOfMemoryError),这类OOM的特点是崩溃时java堆内存和设备物理内存都充足,下文将带你探索并解释这类OOM抛出的原因。文末有demo地址。关键词:OutOfMemoryError,OOM,pthread_createfailede,CouldnotallocateJNIEnv对于每一个移动开发者,内存是都需要小心使用的资源,而线上出现的OOM(OutOfMemoryError)都会让开发者抓狂,因为我们通常仰仗的直观的堆栈信息对于定位这种问题通常帮助不大。网上有很多资料教我们如何“紧衣缩食“的利用宝贵的堆内存(比如,使用小图片,bitmap复用等),可是:1.线上的OOM真的全是由于堆内存紧张导致的吗?2.有没有App堆内存宽裕,设备物理内存也宽裕的情况下发生OOM的可能?内存充裕的时候出现OOM崩溃?3.看似不可思议,然而,最近笔者在调查一个问题的时候,通过自研的APM平台发现公司的一个产品的大部分OOM确实有这样的特征,即:OOM崩溃时,java堆内存远远低于Android虚拟机设定的上限,并且物理内存充足,SD卡空间充足1.线上的OOM真的全是由于堆内存紧张导致的吗?2.有没有App堆内存宽裕,设备物理内存也宽裕的情况下发生OOM的可能?内存充裕的时候出现OOM崩溃?3.看似不可思议,然而,最近笔者在调查一个问题的时候,通过自研的APM平台发现公司的一个产品的大部分OOM确实有这样的特征,即:OOM崩溃时,java堆内存远远低于Android虚拟机设定的上限,并且物理内存充足,SD卡空间充足既然内存充足,这时候为什么会有OOM崩溃呢?二、问题描述在详细描述问题之前,先弄清楚一个问题:什么导致了OOM的产生?下面是几个关于Android官方声明内存限制阈值的API:https://upload-images.jianshu.io/upload_images/14847428-3d883005a97d164c?imageMogr2/auto-orient/strip图2-21通常认为OOM发生是由于java堆内存不够用了,即https://upload-images.jianshu.io/upload_images/14847428-4aa57c25d0b6aff0?imageMogr2/auto-orient/strip图2-2Java堆OOM产生原因这种OOM可以非常方便的验证(比如:通过newbyte[]的方式尝试申请超过阈值maxMemory()的堆内存),通常这种OOM的错误信息通常如下:https://upload-images.jianshu.io/upload_images/14847428-fe245e9d71f66d45?imageMogr2/auto-orient/strip图2-3堆内存不够导致的OOM的错误信息而前面已经提到了,本文中发现的OOM案例中堆内存充裕(Runtime.getRuntime().maxMemory()大小的堆内存还剩余很大一部分),设备当前内存也很充裕(ActivityManager.MemoryInfo.availMem还有很多)。这些OOM的错误信息大致有下面两种:1.这种OOM在Android6.0,Android7.0上各个机型均有发生,文中简称为OOM
一,错误信息如下:https://upload-images.jianshu.io/upload_images/14847428-a515a065887b3afa?imageMogr2/auto-orient/strip图2-4OOM一的错误信息2.集中发生在Android7.0及以上的华为手机(EmotionUI_5.0及以上)的OOM,简称为
OOM二,对应错误信息如下:https://upload-images.jianshu.io/upload_images/14847428-a95b324b3a9868be?imageMogr2/auto-orient/strip(图2-5OOM二的错误信息)3.1代码分析Android系统中,OutOfMemoryError这个错误是怎么被系统抛出的?下面基于Android6.0的代码进行简单分析:1.Android虚拟机最终抛出OutOfMemoryError的代码位于/art/runtime/thread.cchttps://upload-images.jianshu.io/upload_images/14847428-67452129da9038a7?imageMogr2/auto-orient/strip(图3-1ARTRuntime抛出的位置)2.搜索代码可以发现以下几个地方调用了上述方法抛出OutOfMemoryError错误3.第一个地方是堆操作时https://upload-images.jianshu.io/upload_images/14847428-87e1a11baced0462?imageMogr2/auto-orient/strip图3-2Java堆OOM这种抛出的其实就是堆内存不够用的时候,即前面提到的申请堆内存大小超过了Runtime.getRuntime().maxMemory()1.第二个地方是创建线程时https://upload-images.jianshu.io/upload_images/14847428-ec1488a0a4601059?imageMogr2/auto-orient/strip图3-3线程创建时OOM对比错误信息,可以知道我们遇到的OOM崩溃就是这个时机,即创建线程的时候(Thread::CreateNativeThread)产生的。2.还有其他的一些错误信息如“[XXXClassName]oflengthXXXwouldoverflow”是系统限制String/Array的长度所致,不在本文讨论之列。那么,我们关心的就是Thread::CreateNativeThread时抛出的OOM错误,创建线程为什么会导致OOM呢?3.2推断既然抛出来OOM,一定是线程创建过程中触发了某些我们不知道的限制,既然不是Art虚拟机为我们设置的堆上限,那么可能是更底层的限制。Android系统基于linux,所以linux的限制对于Android同样适用,这些限制有:1./proc/pid/limits描述着linux系统对对应进程的限制,下面是一个样例:https://upload-images.jianshu.io/upload_images/14847428-0787ef687868d4ae?imageMogr2/auto-orient/strip(图3-4Linux进程限制示例)用排除法筛选上面样例中的limits:Maxstacksize,Maxprocesses的限制是整个系统的,不是针对某个进程的,排除;Maxlockedmemory,排除,后面会分析,线程创建过程中分配线程私有stack使用的mmap调用没有设置MAP_LOCKED,所以这个限制与线程创建过程无关;Maxpendingsignals,c层信号个数阈值,无关,排除;Maxmsgqueuesize,AndroidIPC机制不支持消息队列,排除。剩下的limits项中,Maxopenfiles
这一项限制最可疑Maxopenfiles表示
每个进程最大打开文件的数目,进程
每打开一个文件就会产生一个文件描述符fd(记录在/proc/pid/fd下面),这个限制表明fd的数目不能超过Maxopenfiles规定的数目。后面分析线程创建过程中会发现过程中涉有及到文件描述符。2.
/proc/sys/kernel中描述的限制这些限制中与线程相关的是/proc/sys/kernel/threads-max,规定了每个进程创建线程数目的上限,所以线程创建导致OOM的原因也有可能与这个限制相关。3.3验证下面对上述的推断进行验证,分两步:本地验证和线上验收。本地验证:在本地验证推断,试图复现与图[2-4]OOM一与图[2-5]OOM二所示错误消息一致的OOM线上验收:下发插件,验收线上用户OOM时确实是由于上面的推断的原因导致的。本地验证实验一: 触发大量网络连接(每个连接处于独立的线程中)并保持,每打开一个socket都会增加一个fd(/proc/pid/fd下多一项)注:不只有这一种增加fd数的方式,也可以用其他方法,比如打开文件,创建handlerthread等等实验预期:当进程fd数(可以通过ls/proc/pid/fd|wc-l获得)突破/proc/pid/limits中规定的Maxopenfiles时,产生OOM;实验结果:当fd数目到达/proc/pid/limits中规定的Maxopenfiles时,继续开线程确实会导致OOM的产生。错误信息及堆栈如下:https://upload-images.jianshu.io/upload_images/14847428-f03d35827ec8ec80?imageMogr2/auto-orient/strip(图3-5FD数超限导致OOM的详细信息)可以看出,此OOM发生时的错误信息确与线上发现的OOM一的“CouldnotallocateJNIEnv”吻合,因此线上上报的OOM一可能就是由FD数超限导致的,不过最终确定需要到线上进行验证(下一小节)。此外从ART虚拟机的Log中看出,还有一个关键的信息“art:ashmem_create_regionfailedfor'indirectreftable':Toomanyopenfiles”,后面会用于问题定位及解释。实验二:创建大量的空线程(不做任何事情,直接sleep)实验预期:当线程数(可以在/proc/pid/status中的threads项实时查看)超过/proc/sys/kernel/threads-max中规定的上限时产生OOM崩溃。实验结果:在Android7.0及以上的华为手机(EmotionUI_5.0及以上)的手机产生OOM,这些手机的线程数限制都很小(应该是华为rom特意修改的limits),每个进程只允许最大同时开500个线程,因此很容易复现了。OOM时错误信息如下:https://upload-images.jianshu.io/upload_images/14847428-d53d49a468d6b3a3?imageMogr2/auto-orient/strip(图3-6线程数超限导致的OOM详细信息)可以看出
错误信息与我们线上遇到的OOM二吻合:"pthread_create(1040KBstack)failed:Outofmemory" 另外ART虚拟机还有一个关键Log:“pthread_createfailed:clonefailed:Outofmemory”,后面会用于问题定位及解释。1.其他Rom的手机线程数的上限都比较大,不容易复现上述问题。但是,对于32位的系统,当进程的逻辑地址空间不够的时候也会产生OOM,每个线程通常需要mapp1MB左右的stack空间(stack大小可以自行设置),32为系统进程逻辑地址4GB,用户空间少于3GB。逻辑地址空间不够(已用逻辑空间地址可以查看/proc/pid/status中的VmPeak/VmSize记录),此时创建线程产生的OOM具有如下信息:https://upload-images.jianshu.io/upload_images/14847428-262a6f7dc0eb901f?imageMogr2/auto-orient/strip(图3-7逻辑地址空间占满导致的OOM)线上验收及问题解决本地尝试复现的OOM错误信息中图[3-5]与线上OOM一情况比较吻合,图[3-6]与线上OOM二的情况比较吻合,但线上的OOM一真的时FD数目超限,OOM二真的是由于华为手机线程数超限的原因导致的吗?最终确定还需要取线上设备的数据进行验证。验证方法:下发插件到线上用户,当Thread.UncaughtExceptionHandler捕获到OutOfMemoryError时记录/proc/pid目录下的如下信息:1./proc/pid/fd目录下文件数(fd数)2./proc/pid/status中threads项(当前线程数目)3.
OOM的日志信息(出了堆栈信息还包含其他的一些warning信息线上OOM一验证发生OOM一的线上设备中采集到的信息:1./proc/pid/fd目录下文件数与/proc/pid/limits中的Maxopenfiles数目持平,证明FD数目已经满了;2.崩溃时日志信息与图[3-5]基本一致;由此,证明
线上的OOM一确实是由于FD数目过多导致的OOM,推断验证成功。OOM一的定位与解决:最终原因是App中使用的长连接库再某些时候会有瞬时发出大量http请求的bug(导致FD数激增),已修复。线上OOM二验证 集中在华为系统的OOM二崩溃时收集到的信息样例如下,(收集的样例中包含的devicemodel有VKY-AL00,TRT-AL00A,BLN-AL20,BLN-AL10,DLI-AL10,TRT-TL10,WAS-AL00等):1./proc/pid/status中threads记录全部到达上限:Threads:500;2.崩溃时日志信息与图[3-6]基本一致;推断验证成功,即
线程数受限导致创建线程时clonefailed导致了线上的OOM二。OOM二的定位与解决:关于App业务代码中的问题还在定位修复中。3.4解释下面从代码分析本文描述的OOM是怎么发生的,首先线程创建的简易版流程图如下所示:https://upload-images.jianshu.io/upload_images/14847428-0331ac7d58251d85?imageMogr2/auto-orient/strip(图3-8线程创建流程)上图中,线程创建大概有两个关键的步骤:第一列中的
创建线程私有的结构体JNIENV(JNI执行环境,用于C层调用Java层代码)第二列中的
调用posixC库的函数pthread_create进行线程创建工作下面对流程图中关键节点(图中有标号的)进行说明:1.图中节点①,/art/runtime/thread.cc中的函数Thread:CreateNativeThread部分节选代码如下:https://upload-images.jianshu.io/upload_images/14847428-3ea4a86d26199c49?imageMogr2/auto-orient/strip(图3-9Thread:CreateNativeThread节选)可知:JNIENV创建不成功时产生OOM的错误信息为"CouldnotallocateJNIEnv",与文中OOM一一致pthread_create失败时抛出OOM的错误信息为"pthread_create(%sstack)failed:%s".其中详细的错误信息由pthread_create的返回值(错误码)给出。错误码与错误描述的对应关系可以参见bionic/libc/include/sys/_errdefs.h中的定义。文中OOM二的具体错误信息为"Outofmemory",就说明pthread_create的返回值为12。https://upload-images.jianshu.io/upload_images/14847428-689ad98d836934d0?imageMogr2/auto-orient/strip图3-10系统错误定义_errdefs.h2.图中节点②和③是创建JNIENV过程的关键节点,节点②/art/runtime/mem_map.cc中函数MemMap:MapAnonymous的作用是为JNIENV结构体中Indirect_Reference_table(C层用于存储JNI局部/全局变量)申请内存,申请内存的方法是节点③所示的函数ashmem_create_region(创建一块ashmen匿名共享内存,并返回一个文件描述符)。节点②代码节选如下:https://upload-images.jianshu.io/upload_images/14847428-e301d11b23f40872?imageMogr2/auto-orient/strip(图3-11MemMap:MapAnonymous节选)我们线上的OOM一的错误信息"ashmem_create_regionfailedfor'indirectreftable':Toomanyopenfiles",与此处打印的信息吻合。"Toomanyopenfiles"的错误描述说明此处的errno(系统全局错误标识)为24(见图[3-10]系统错误定义_errdefs.h)。由此看出我们线上的OOM一是由于文件描述符数目已满,ashmem_create_region
无法返回新的FD而导致的。3.图中节点④和⑤是调用C库创建线程时的环节,创建线程首先调用__allocate_thread函数申请线程私有的栈内存(stack)等,然后调用clone方法进行线程创建.申请stack采用的时mmap的方式,节点⑤代码节选如下:https://upload-images.jianshu.io/upload_images/14847428-f4e447c20717be2e?imageMogr2/auto-orient/strip(图3-12__create_thread_mapped_space节选)打印的错误信息与图[3-7]中进程逻辑地址占满导致的OOM错误信息吻合,图[3-7]中错误信息"Tryagain"说明系统全局错误标识errno为11(见图[3-10]系统错误定义_errdefs.h). pthread_create过程中,节点4相关代码如下:https://upload-images.jianshu.io/upload_images/14847428-3292f4df5e5e2121?imageMogr2/auto-orient/strip(图3-13pthread_create节选)此处输出的错误日志"pthread_createfailed:clonefailed:%s"与我们线上发现的OOM二吻合,图[3-6]中的错误描述"Outofme
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 保安证知识要点提炼试题及答案
- 西安英语抽考题目及答案
- 吉林省海门市重点名校2024届中考猜题数学试卷含解析
- 建湖实中教育集团达标名校2024届中考数学考前最后一卷含解析
- 水电工施工方案
- 山东大学《信息检索与阅读》2023-2024学年第一学期期末试卷
- 广西工程职业学院《人权法》2023-2024学年第二学期期末试卷
- 濮阳医学高等专科学校《皮肤性病护理学》2023-2024学年第二学期期末试卷
- 2025年广东省广州市广东第二师范学院番禺附中高三第二次模拟考试试卷历史试题含解析
- 广西信息职业技术学院《短片写作》2023-2024学年第二学期期末试卷
- 子宫肌瘤的超声诊断
- 从电影《第二十条》中学习刑法
- 大学物理-质点动力学
- 智慧建筑评价标准
- 社会稳定风险评估 投标方案(技术标)
- 体育公园配置要求
- 2024年新青岛版(六三制)六年级下册科学全册知识点
- 标识标牌制作安装实施方案
- 五年级下册数学计算题100道及答案
- 《如何提高自信心》课件
- 脊柱侧弯的中医治疗研究
评论
0/150
提交评论