有趣生活

当前位置:首页>科技>android系统打开支付宝支付宝客户端OOM专项优化实践

android系统打开支付宝支付宝客户端OOM专项优化实践

发布时间:2026-07-21阅读(1)

导读一、背景:作为一名Android程序开发者,在日常的代码开发工作中可能不会过多关注自己业务对内存的使用是否合理,通常情况下Android系统的内存管理机制帮....一、背景:

作为一名Android程序开发者,在日常的代码开发工作中可能不会过多关注自己业务对内存的使用是否合理,通常情况下Android系统的内存管理机制帮我们处理好了内存的分配和回收。然而在一些异常场景下不合理的内存占用不仅会使用户应用程序运行卡顿、ANR、黑屏,在极端情况下还会发生 OOM(Out of Memory)崩溃,极大影响用户体验造成用户流失。通常我们在对待线上的的Out of Memory的闪退都会被当做小概率事件没有被有效重视和系统分析,本文将结合支付宝线上OOM真实案例详细的介绍下常见OOM问题的根因分析和优化实践。

在支付宝应用架构的不断演进中用户支付场景已经是最基础的使用场景,随着小程序生态的引入森林庄园等复杂h5/小程序的使用比例不断增长,同时理财、本地生活等重度业务也运行在支付宝这艘航母上,并且在每年的大促活动像双11、618、新春五福活动上线后让本就不富裕的内存空间又雪上加霜,在2020年之前支付宝的内存问题一直未被重点关注,从一组数据可以看到在过去的19-20财年中,客户端OOM闪退率暴涨了近一倍,占整体客户端闪退的45%以上,内存水位则涨幅在300M左右,按照这个趋势20年底的OOM闪退率会涨幅50%。那到底是什么原因导致的支付宝OOM问题如此严重呢?这里先抛出几个问题:

  1. 线上低端机的OOM问题是否真的比高端机更严重呢?
  2. 线上的OOM真的全是由于Java内存泄漏导致的堆内存紧张导致的吗?
  3. 线上OOM有没有可能在App堆内存宽裕,设备物理内存也宽裕的情况下发生?
二、OOM问题根因分析2.1 OOM分类

通过以下数据我们可以看到在支付宝32位包的OOM闪退中9-11系统的占比远远超过6.x以下机器,并且在对闪退时内存统计中发现5.x以上机器闪退时端上整体内存值还有大量剩余,而虚拟内存空间几乎达到了2^32=4GB。

众所周知32位应用程序的虚拟内存寻址上限只有 2^32=4GB,无论高端机还是低端机只要虚拟内存寻址达到这个上限就会触发系统OOM闪退,通常在logcat日志中会看到"OutOfMemoryError: pthread_create (1040KB stack) failed: Try again", "libc abi: terminating with uncaught exception of type St9bad_alloc: std::bad_alloc","Could not mmap handle 0x67ae34d0 fd=652 (Out of memory)"等。因此按照不同的成因我们总结了OOM问题分类,只有对线上OOM问题清晰的认识和分类才能更好的感知问题变化和有针对性的治理

2.2 虚拟内存地址指标量化

下面将会从虚拟内存结构入手详细地讲解一下导致虚拟内存寻址空间不足的原因,从下图内存结构看出去系统占据的1G外剩下3GB内存都是如何分配?通常我们在写 Native 代码的时候,并不会直接调用内核的 API 去申请物理内存,而是使用 malloc 族的函数进行内存申请,这时候返回的指针是指向虚拟内存中的地址空间,之后在这部分地址空间真的被使用的时候,才会发生缺页中断触发真实的物理内存分配,所以通常是两层分配结构,用户态的代码申请的内存来自于内存分配器的二次分配,常见的内存分配器有 JeMalloc、TcMalloc、PtMalloc 等等。这里也解答了上面的问题,手机物理内存或javaheap内存只使用不到50%的情况下,虚拟内存可能已经打满同样会触发OOM闪退。

三、线上监控&问题感知

那么虚拟内存的使用应该如何度量呢?简单的方式是直接从/proc/{pid}/status文件读取vmsize数据,但如果要做到能感知线上内存水位变化并快速定位问题还需要更细粒度的分类。如上图所示,通过对/proc/{pid}/maps地址文件的内存分配标记进行分类可量化成20 个细粒度内存指标,在支付宝启动后的内存空间分析中可以看到在支付宝启动后留给业务的内存空间大概在1-2G左右,如果没有有效的内存监控释放手段,随着应用使用时长的增加,内存地址空间会被迅速耗尽。下面会介绍线上主要的几个内存监控方式。

3.1 支付宝全局虚拟内存水位监控

基于虚拟内存的水位监控主要作用是感知活动或者开关变更导致的内存上涨,同时能确定业务维度的内存水位变化,通过制定告警阈值,让线上问题定位达到分钟级别。

3.1.1 典型案例:首页氛围图和腰封 Lottie 动画

大促活动期间首页氛围图或腰封上线lottie动图引起的Libcmalloc上涨约涨20-50M,导致OOM闪退率上涨30%,相比业务上线活动首页氛围和腰封的变更影响是全局的基础水位,对OOM闪退率影响较大。下图为某次活动0点发布氛围后支付宝整体内存水位上涨40M。针对这一问题我们对所有lottie上线资源做了动态的内存检测,超过阈值则被禁止上线,同时通过线下的内存检测结果可预估lottie上线后对线上闪退率的影响

0点活动上线内存水位上涨

线上闪退率预估

3.1.2 典型案例:大促活动

随着渲染技术迭代新春五福,双11活动的页面动画特效复杂度越来越高,已经不再局限于2D动画,并且活动页会为支付宝内其他业务引流,当用户不断跳转页面访问时内存可能不会及时释放,导致短时间的内存叠加效应引起内存水位升高同时OOM闪退率上涨。针对这一问题,支付宝活动都会针对渲染特效设计几种降级方式,在内存水位变化幅度超过阈值或OOM闪退率上涨情况下可以对业务进行统一降级,动画->静态图,3D->2D等

3.1.3 典型案例:Dexpatch

Dexpatch发布引起的端整体Public-File水位上涨50M左右,由于Dexpatch本身的实现方式要在native解包和替换,导致mmap了大量内存,目前在32位包已经不再使用Dexpatch热修复。下图是线下测试结果:

3.1.4 典型案例:uc内核解压

uc压缩内核推动动态bundle,通过用户日志可以发现so解压后出现错误,导致用户重复进行初始化进而导致Public-Files内存上涨后触发OOM闪退。在推送回滚后,整体崩溃率下降。

3.1.5 典型案例:蚂蚁庄园

蚂蚁庄园3周年活动,生活号文章插入超大gif动图导致GPU增幅超过300M引起线上OOM闪退告警,暴露了目前对于h5/小程序中的大图、视频和动图没有提前发现的能力。基于这个问题在对业务准入的时候增加图片视频的静态尺寸检测和动态内存检测,避免类似问题再次发生。

小程序/H5中资源与内存使用关系梳理:高清大图内存主要分配在gpu上,随便下载了一些文章详情的图片发现大小都在1MB以内,这是因为图片都是有压缩的,但是在手机中图片显示是完全解压状态,正常情况图片的内存计算方式:

  • png = 像素总数(图片宽×高) × 4 Byte per pixel × 1~3(渐进式、缩放缓存、纹理尺寸、mipmap限制等因子影响),因此高清大图应控制分辨率,按需使用适当尺寸的图片,禁止超高分辨率图片
  • gif图片内存主要分配在Gpu上,由于gif采用多帧轮播的方式播放,gif所有帧内存都会加载到gpu中且无法释放,其内存计算方式是:
    • GIF = 像素总数(图片宽×高) × 4 Byte per pixel × 总帧数 × 1~2(纹理尺寸、mipmap限制等因子影响)
    • 典型案例:分辨率690*4746,帧数21,文件大小346KB直接占用GPU 210MB,该图仅最上面是动图,而全图使用gif格式并且以超长图展示,线下测试手机需要至少10s才能加载出该图。应该严格限制此类情况发生
3.2 运行时业务维度内存异常监控

在监控内存水位的同时,我们还要掌握每个业务生命周期内分配的内存空间是否合理,目前做法是通过开关配置一组内存指标异常值,当业务单次采样间隔内存分配超过阈值时上报相关数据,概数据帮助我们在线下推动业务对内存使用优化,同时配合线上告警机制保证业务内存使用变化时能快速感知到。

典型案例:

线上监控到某选图打印的小程序单次的Libcmalloc增幅超过300M,导致该应用OOM闪退率是正常业务的20倍,主要原因有2点:

    1. 用户在使用小程序时会选择一张手机图片,在多媒体选图组件做图片预览和大图展示时为了加快图片展示提前加载了选图前后2张,由于图片加载内存全部分配在Native导致Libcmalloc内存大幅上涨,个别用户涨幅超过1G
    2. 多媒体组件没有监听小程序退出事件,因此没有及时做内存回收导致缓存的图片数据长时间在内存中保存

3.3 闪退时刻的端上运行环境数据记录在内存问题排查中至关重要

支付宝微镜平台提供了闪退issue的查看和分析能力,我们只需在客户端闪退时按照一定格式将端上运行时数据记录到埋点即可在平台查看到聚合后的数据

  • 临近闪退时的内存snapshot及闪退时刻内存数据记录,方便排查闪退前的内存变化趋势和闪退时内存数据聚合分析
  • 部分maps原始地址数据,隐藏了内存中异常信息
  • 完整的虚拟地址解析后结构,如下图

Moudles Moudles-Ashmem Moudles-JavaVM Moudles-Native-Anonymous Moudles-Native-Bss Moudles-Native-LibcMalloc Moudles-Native-Other Moudles-OtherPublic Public-Devices Public-Files Public-Gpu Public-ThreadsU4Core U4Core-BlinkGC U4Core-PartitionAlloc U4Core-SharedMemory U4Core-UCMalloc U4Core-v8 Heap

典型案例:
  1. MIUI Android 10 系统字体重复占用虚拟内存,导致支付宝 App 可用的虚拟内存变少,更容易发生崩溃(发生OOM)。支付宝在20年的双十一活动的 OOM 中,小米 红米机型占比 43%,高于小米手机的市占率
  2. 某外卖小程序在使用v8 worker的时候调用message port发给render进程大量消息并使用了sharedmemory导致闪退率上涨

四、内存诊断&治理4.1 Native内存问题治理

支付宝是一个汇集了扫码,端智能,AR,小程序容器,音视频播放等 native 代码非常多的大型应用,据不完全统计有100个so在支付宝内运行,每个 native 代码相关的模块背后都有一个专业团队在高速迭代,Java 堆内存因为有比较成熟的工具和方法论,加上 hprof 快照作为补充,定位和治理都很方便,native 内存问题一直缺乏高效稳定的工具导致问题治理难度非常大。事实上,单纯的native内存泄漏问题相对较少,更多的是因为业务逻辑不合理带来的内存使用问题,需要工具渗透到 App 运行的过程中进行监控,对工具性能和稳定性提出更高的要求。

因此对于支付宝的 native 内存泄漏监控工具的诉求主要有以下几个方面:

  1. 接入成本:无需额外适配Android 版本,无需 root
  2. 稳定性:几乎不影响业务的稳定性问题,可以满足灰度版本开启即可
  3. 性能层面:对业务运行和启动都没有明显劣化影响,无卡顿和ANR问题
  4. 监控范围:不局限于 malloc/calloc/realloc/memalign/free,至少还能覆盖 mmap/mmap64/munmap
  5. 支撑广度:内存监控,内存泄漏,野指针检测等
1. 工具调研

Copyright © 2024 有趣生活 All Rights Reserve吉ICP备19000289号-5 TXT地图HTML地图XML地图