目录

Resource Leak(资源泄漏)检测

简介

资源泄漏是指句柄、线程或内存等资源,在应用运行过程中没有被正确释放,导致资源被长期占用且无法被其他应用使用,如果某一类资源耗尽,系统可能出现卡死或重启等异常情况。为了应对资源泄漏问题,系统会提供资源泄漏检测、判决、维测日志抓取、日志上报的能力,为开发者提供详细的维测日志以辅助故障定位。本文将主要介绍资源泄漏检测的实现原理以及资源泄漏日志的规格。

基本概念

资源泄漏主要分为三类:内存泄漏、句柄泄漏和线程泄漏。对于每种泄漏,系统会通过周期采样的方式对进程的资源使用情况进行检测,如果资源使用超过阈值,会抓取对应维测日志并上报泄漏事件。通过Hiappevent资源泄漏事件进行订阅,订阅方法详见资源泄漏事件。

实现原理

资源泄漏具体检测方式如下:

泄漏类型 检测机制
句柄泄漏(FD_LEAK) 每隔60s遍历一次进程,获取进程fd句柄总数,超过阈值(5000个) 时抓取详细句柄信息,同步上报泄漏。
线程泄漏(THREAD_LEAK) 每隔60s遍历一次进程,获取进程的总线程数,超过阈值(700个) 时抓取详细线程名信息,同步上报泄漏。
内存泄漏(MEMORY_LEAK) - JS泄漏(JS_LEAK) 虚拟机内部进行插桩,当堆内存的使用率超过85%或者触发OOM时会抓取heapdump,同步上报该故障。
内存泄漏(MEMORY_LEAK) - native内存泄漏(PSS_MEMORY) 以应用进程平均动态峰值内存作为基线,以200s作为基准,当动态内存峰值超过基线值2倍时,判定泄漏,同时触发管控。
内存泄漏(MEMORY_LEAK) - ASHMEM/DMA(ION)/GPU等内存泄漏(KERNEL_MEMORY) 基于ASHMEM/DMA(ION)/GPU的基线值,超过基线值时会判定泄漏,同步抓取维测信息。
  1. 表格中所述阈值/基线均为系统默认,如果生态在开发过程中需要自行设定基线,可以使用hidebug.setAppResourceLimit()接口进行设置,该接口建议在开发阶段调用,不要在正式发布阶段使用。

  2. 虚拟机内存使用率计算公式 = heapUsed / totalHeap。

    heapUsed:当前虚拟机使用的堆大小,单位:KB。可通过hidebug.getAppVMMemoryInfo()接口获取。

    totalHeap:当前虚拟机的堆总大小,单位:KB。可通过hidebug.getAppVMMemoryInfo()接口获取。

  3. 当应用上报JS_ERROR/CPP_CRASH故障,Error message包含“OutOfMemory”时,可参考内存泄漏分析方法辅助定位。

  4. 管控是指当系统判定应用发生泄漏后,主动终止泄漏应用的行为。

  5. 在资源泄漏资料中,DMA、ION、dmaheap、dmabuf 可理解为同一种内存类型,不作强区分。本篇文档均采用DMA(ION)统一表达。

资源泄漏内核管控方式如下:

从HarmonyOS 6.1.0开始,应用资源申请过快或前台泄漏导致整机资源不足,比如单应用快速申请(RSS、DMA(ION)、GPU内存)超过阈值,导致整机出现低内存,系统会对应用进行管控,同步提供部分基础的RESOURCE_OVERLIMIT维测信息。

  1. 当前支持内核管控的资源类型有:DMA(ION)、GPU、RSS、ASHMEM、THREAD。

  2. 内核管控不区分前后台,可能会出现问题应用的前台闪退问题。

约束和限制

  1. 句柄泄漏调用栈、native内存泄漏调用栈、js泄漏内存快照等维测因为开销较大,所以在nolog版本默认不开启。

  2. 如果开发者希望获取到nolog版本的js泄漏内存快照,可参考资源泄漏事件订阅(ArkTS)增加对nolog版本js内存快照的订阅。

日志获取

资源泄漏日志由LeakDetector模块进行管理,可通过以下方式获取:

句柄泄漏日志规格

故障日志文件名:[pid]_fd_leak.txt(方式一)或RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

[h2]日志头部信息

字段 说明
time 故障发生时间。
pid 发生故障进程的pid,可以用于在流水日志中搜索相关进程信息。
process 应用进程包名。
leaked fd nums 判定泄漏时获取的句柄数量(快照)。
time: 2024/06/27 11:55:28
pid: 1380
process: process1
leaked fd nums: 5111

[h2]句柄类型详细信息

[h2]特殊类型句柄维测信息

如果Leaked fd Top 10的TOP句柄信息属于ashmem/socket/pipe/sync_file/dmabuf这五类特殊类型,且该类型的句柄个数超过1000个,日志中会增加整机详细的维测信息,具体如下:

[h2]句柄栈信息

当判定句柄泄漏后,会hook该进程的pipe/open等系统调用10分钟,抓取调用栈,并基于相同调用栈聚类。如下每一行都是一个调用栈,调用顺序为从右到左,其中num后面的数字表示调用栈总个数,bt后面为具体调用栈。具体栈信息可通过addr2line解析到对应的函数。

*****************************
LOGGER_MEMCHECK_FD_STACK_INFO
pid: 12326
get stack time: 2024/06/17 19:16:48
==============================FdTrack Stack==============================
Generated by HiviewDFX @HarmonyOS
==============================Sorted by num==============================
num 8272 bt [/system/lib64/libfdleak_tracker.so+0x1fb58] [/system/lib/ld-musl-aarch64.so.1+0x1d3154] [/system/lib/ld-musl-aarch64.so.1+0x148940] [/system/lib64/platformsdk/libuv.so+0x1ab30] [/system/lib64/platformsdk/libuv.so+0x1cbd0] [/system/lib64/module/file/libfs.z.so+0x17109c] [/system/lib64/module/file/libfs.z.so+0x170af4] [/system/lib64/module/file/libfs.z.so+0x1701c8] [/system/lib64/platformsdk/libace_napi.z.so+0x34828]
num 3968 bt [/system/lib64/libfdleak_tracker.so+0x1fb58] [/system/lib/ld-musl-aarch64.so.1+0x1d3154] [/system/lib64/platformsdk/libipc_core.z.so+0x4ac64] [/system/lib64/platformsdk/libbackup_kit_inner.z.so+0x532d4] [/system/lib64/platformsdk/libbackup_kit_inner.z.so+0x4f8fc] [/system/lib64/platformsdk/libipc_core.z.so+0x38420] [/system/lib64/platformsdk/libipc_core.z.so+0x4e99c] [/system/lib64/platformsdk/libipc_core.z.so+0x4eb34] [/system/lib64/platformsdk/libipc_core.z.so+0x4edc8]
num 3968 bt [/system/lib64/libfdleak_tracker.so+0x1fb58] [/system/lib/ld-musl-aarch64.so.1+0x1d3154] [/system/lib64/platformsdk/libipc_core.z.so+0x4ac64] [/system/lib64/platformsdk/libbackup_kit_inner.z.so+0x532b0] [/system/lib64/platformsdk/libbackup_kit_inner.z.so+0x4f8fc] [/system/lib64/platformsdk/libipc_core.z.so+0x38420] [/system/lib64/platformsdk/libipc_core.z.so+0x4e99c] [/system/lib64/platformsdk/libipc_core.z.so+0x4eb34] [/system/lib64/platformsdk/libipc_core.z.so+0x4edc8]
  1. 这里统计的是10分钟内全量申请句柄的调用栈,并没有将已经close的去掉。

  2. 栈信息只有在log版本直接存在;nolog版本若未开“开发者模式”,则不抓取栈信息,如果发现不存在栈信息,需要在“开发者选项”中打开“系统资源泄漏日志”,并重启设备,来使能资源泄漏的抓栈功能。

[h2]句柄泄漏聚类规则

应用程序在同一或不同版本上、不同时间产生的泄漏问题可能为同一原因,开发者可以从故障日志中提取故障特征,根据故障特征将多份故障日志进行聚类,以提高泄漏问题的分析效率。

  1. 通过句柄泄漏日志中的top10的文件句柄数以及top10的文件路径句柄数判定是哪种类型的句柄泄漏,将占比最多的句柄类型作为本次故障的故障特征。

  2. ASHMEM、DMA(ION)等特殊类型句柄,可参考ASHMEM_LEAK、ION_LEAK规则进行聚类。

线程泄漏日志规格

故障日志文件名:[pid]_thread_leak.txt(方式一)或RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

[h2]日志头部信息

字段 说明
time 检测到线程泄漏的时间。
pid 发生故障进程的pid,用于在流水日志中查询相关进程信息。
vss 单个进程全部可访问的地址空间,其大小可能包括还尚未在内存中驻留的部分,单位:KB。
rss 单个进程实际占用的内存大小,包括该进程所使用共享库全部内存大小,单位:KB。
process 发生故障的应用包名。
summary 判定泄漏时进程线程总数。
time: 2024/06/27 03:45:19
pid: 41897
vss: 12783644
rss: 2229352
process: process1
summary: 879

[h2]线程类泄漏详细信息

[h2]线程泄漏聚类规则

应用程序在同一或不同版本上、不同时间产生的泄漏问题可能为同一原因,开发者可以从故障日志中提取故障特征,根据故障特征将多份故障日志进行聚类,以提高泄漏问题的分析效率。

  1. 分析线程泄漏日志中展示的top10线程,将占比最多的线程名作为本次故障的故障特征。

    系统已对同名线程进行了聚类,但是部分特殊场景下,线程名间可能会存在差异,如“IPC_11_13795”、“IPC_12_13796”,如果开发者希望进一步增强聚类效果,可以将全量线程中的相似进程名作为同一个故障特征,如“IPC_xx_xxx”,以提高聚类准确性。

  2. 从线程泄漏日志中提取出线程对应的线程快照,并根据调用栈进行聚类。

JS内存泄漏日志规格

故障日志文件名: memleak-js-[process_name]-[pid]-[tid]-[timestamp].rawheap(方式一)或RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

[h2]JS泄漏聚类规则

应用程序在同一或不同版本上、不同时间产生的泄漏问题可能为同一原因,开发者可以从故障日志中提取故障特征,根据故障特征将多份故障日志进行聚类,以提高泄漏问题的分析效率。

聚类步骤描述

  1. 确认聚类范围,只聚类top20目录和retained size占5%以上的目录。

  2. 通过聚类规则上报的故障进行聚类。为了保证聚类结果的有效性,不同目录下存放的对象不同,聚类规则也不同。

  3. 统计各类对象的数量及内存大小,按照对象的数量或内存大小进行排序,找到内存占比最高的对象,作为本次上报故障的故障特征。

聚类规则

聚类规则主要分为三种:名称聚类,引用链聚类和属性聚类。不同类型的对象需要使用不同的聚类方法。

  1. 名称聚类(通过对象名称进行聚类)

    Function(closure)目录下的对象,按照对象名称聚类,当名称相同时,视为一类。

  2. 引用链聚类(通过对象的最短引用链聚类)

    Method,js_set,Map,string和JSNativePointer等目录下的对象,优先通过引用链聚类。该类对象目录下名称一致,通过引用链可以区分对象创建场景。对比目录下各对象到GC ROOT的最短引用链(如果有多条最短引用链则选择retained size最大的那条引用链),最短引用链相同,则视为一类。

  3. 对象名称+引用链聚类

    各类业务对象(业务侧创建的类对象和函数对象)带有路径对象名称和行号信息。相同的类或函数对象调用点不同,则引用链不同,需要根据不同的调用点进行区分。

    此外,framework,jsarray(array)也通过对象名称+引用链聚类。

  4. 属性+引用链聚类

    jsobject(js_shared_object)目录下对象名称相同,但代表的对象并不一致,需要通过引用链对jsobject对象进行分类,即对不同调用点的jsobject进行区分。

    jsobject对象中存在大量distance为1的对象,这些对象无法通过引用链区分,但可以通过属性进行区分,即直接持有的对象是否一致,如果jsobject对象直接持有的对象名称都相同,且持有关系也相同,则归为一类。

  5. 特殊聚类

    5.1 SourceTextModule

    SourceTextModule对象是系统侧创建的,用于持有export对象。每个ts文件会对应生成一个SourceTextModule对象,持有该ts文件中export的对象,因此天然就已经是聚类后的结果,不需要再次聚类。

    5.2 Promise/PromiseRecord/PromiseCapability/PromiseReaction

    异步相关的对象,请根据PromiseReaction下的handle信息+引用链进行聚类。PromiseReaction下的handle信息代表了该异步任务的上一个任务,可以通过上一个任务进行区分。

    5.3 proxy

    proxy往往与框架对象强相关,可以通过proxy下的target信息(handle)+引用链进行聚类。proxy下的target信息代表了proxy持有的被代理对象,proxy本身无意义,需要根据被proxy代理的对象进行区分。

  6. 除上述类型外的其他基本类型:

    其他基本类型对象默认按照最短引用链聚类。

native内存泄漏日志规格

故障日志文件名: 泄漏日志获取中方式一和方式三文件名不同,方式三为RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log,根据内容区分,方式一如下所示:

[h2]内存采样

日志文件:memleak-native-[process_name]-[pid]-sample.txt,里面展示了进程号,进程名,基线值,内存采样的情况,可以直观的观察到内存的变化情况。

字段 说明
SoftThreshold 系统设定的该进程基线(也可由应用自身通过setAppResourceLimit接口设置),应用内存连续五次超过进程基线即上报内存泄漏事件,单位:KB。
HardThreshold 系统设定的进程硬门限,应用内存连续两次超过硬门限即上报内存泄漏事件,单位:KB。
PSS 按比例计算的驻留内存大小,共享库的内存按进程数均摊(带*的时间精准计算一次进程的PSS使用量),单位:KB。
Offset 将共享库内存均摊后的偏差:RSS + Offset = PSS (用于矫正后续不带*号的PSS估算值) ,单位:KB。
RSS 进程实际驻留在物理内存中的内存总量(包含共享库占用的全部内存),单位:KB。
SwapPSS 进程实际交换出去(即写入swap空间)的内存总量,单位:KB。
TotalPSS 进程PSS使用量的总和,单位:KB。
AvcMem 进程通过Avcodec_service创建编解码实例创建的内存,由Avcodec_service上报给hiview进行统计,单位:KB。
MediaMem 进程通过Media_service接口创建的内存,由Media_service上报给hiview进行统计,单位:KB。
GPU 进程使用GPU内存,单位:KB。
ION 进程使用ION内存,单位:KB。
TotalMem 进程使用的TotalPSS+ION+GPU+AvcMem+MediaMem内存的总和,单位:KB。
Level 当前进程的泄漏等级简写。
RunningTime 进程当前生命周期,单位:s。
Realtime 当前采样的真实时间。
/*************************************************************
/*                  ***** READ ME *****                      *
/*************************************************************
/*                 RSS: Resident Set Size                    *
/*                 PSS: Proportional Set Size                *
/*                 RSS + Offset = PSS                        *
/*                 TotalPSS = PSS + SwapPSS                  *
/*   TotalMem = TotalPSS + Av_Mem + Media_Mem + ION + GPU    *
/*                 ***** Two Modes *****                     *
/*      Estimate Mode: RSS & SwapPSS is real                 *
/*      Real Mode(Realtime with *): everything is real       *
/*      Media_rss:apply mem through media_service            *
/*      Avc_rss:apply mem through avcodec_service            *
/*    ~ means negligible memory(safe to ignore in analysis)  *
/*************************************************************
/*                   ***** Attention *****                   *
/*    Formulas about TotalMem and sub-items may change,      *
/*    please reference current annotation formula            *
/*************************************************************

pid: XXXX
processName: XXXXXX
SoftThreshold: 3500(KB)
HardThreshold: 1024000(KB)

Index   RSS(KB)     Offset(KB)  PSS(KB)     SwapPSS(KB)     TotalPSS(KB)     MediaMem(KB)   AvcMem(KB)    GPU(KB)       ION(KB)       TotalMem(KB)     Level   RunningTime(s)     Realtime
1       14668       0           14668       5500            20168            ~              ~             ~             ~             20168            W       112             2025/04/23 12:28:02
2       12732       0           12732       5476            18208            ~              ~             ~             ~             18208            W       352             2025/04/23 12:32:01
3       13560       0           13560       5456            19016            ~              ~             ~             ~             19016            W       592             2025/04/23 12:36:02
4       13576       0           13576       5440            19016            ~              ~             ~             ~             19016            W       832             2025/04/23 12:40:02
5       13576       0           13576       5440            19016            ~              ~             ~             ~             19016            W       1072            2025/04/23 12:44:02
6       13584       -8320       5264        5440            10704            ~              ~             ~             ~             10704            W       1072            *2025/04/23 12:44:02
7       12984       -8320       4664        5084            9748             ~              ~             ~             ~             9748             W       1312            2025/04/23 12:48:02

[h2]内存维测

日志文件:memleak-native-[process_name]-[pid]-smaps.txt

字段 说明
RealPssMemory 记录了realtime时刻采集的PSS值,单位:KB。
LOGGER_MEMCHECK_MEMINFO 下方记录了整机meminfo内存信息,如MemTotal、MemFree等。
LOGGER_MEMCHECK_SMAPS_INFO 下方记录了该进程的smaps汇总信息。
LOGGER_MEMCHECK_SAMPLE_NMD_INFO 下方记录了该进程的两次jemalloc的申请情况(两次记录间隔5min),系统会根据两次NMD信息抓取内存栈。
LOGGER_MEMCHECK_DETIAL_INFO 下方记录了该进程的jemalloc快照详细信息。
Generated by HiviewDFX @HarmonyOS
LOGGER_MEMCHECK_GERNAL_INFO
 pidNumber: 2017
 processName: process1
 PidStartTime: 1602
 RealPssMemory: 83505

*****************************
LOGGER_MEMCHECK_MEMINFO
MemTotal:                             11332540 kB
MemFree:                               1686056 kB
......

LOGGER_MEMCHECK_SMAPS_INFO
-------------------------------[memory]-------------------------------
                                    Shared      Shared      Private     Private
Size        Rss         Pss         Clean       Dirty       Clean       Dirty       Swap        SwapPss     Counts                        Name
2048        0           0           0           0           0           0           0           0           1                             /dev/__parameters__/param_sec_dac
...
45778196    744068      827123      213560      55288       403304      71916       308888      308888      6500                          Summary
......

LOGGER_MEMCHECK_SAMPLE_NMD_INFO

            size       allocated         nmalloc         ndalloc

               8           17384          511848          509675
              16          129376          338438          330352
              32         1138816         1026155          990567
              48         3161808         1322095         1256224
              64         1869376          908151          878942
......

************ endl ************

LOGGER_MEMCHECK_SAMPLE_NMD_INFO

            size       allocated         nmalloc         ndalloc

               8           17384          511848          509675
              16          129376          338438          330352
              32         1138816         1026155          990567
              48         3161808         1322095         1256224
              64         1869376          908151          878942
......

************ endl ************

*****************************
LOGGER_MEMCHECK_PROC_INFO
ASHMEM_PROCESS_INFO
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
Process_name Process_ID Fd Cnode_idx Applicant_Pid Ashmem_name Virtual_size Physical_size magic
XXXXX           816             22      328234  816     dev/ashmem/PolicyVolumeMap      541             4096            7
************ endl ************

******************************
LOGGER_MEMCHECK_DETIAL_INFO
allocated         nmalloc   (#/sec)         ndalloc   (#/sec)       nrequests   (#/sec)           nfill   (#/sec)          nflush   (#/sec)
small:                      183785560        12591759       619        10371251       510         1289491        63         1313204        64          956094        47
large:                       31059968            3359         0            2946         0            3359         0            3359         0               0         0
total:                      214845528        12595118       619        10374197       510         1292850        63         1316563        64          956094        47

......

bins:           size ind    allocated      nmalloc (#/sec)      ndalloc (#/sec)    nrequests   (#/sec)  nshards      curregs     curslabs  nonfull_slabs regs pgs   util       nfills (#/sec)     nflushes (#/sec)       nslabs     nreslabs (#/sec)      n_lock_ops (#/sec)       n_waiting (#/sec)      n_spin_acq (#/sec)  n_owner_switch (#/sec)   total_wait_ns   (#/sec)     max_wait_ns  max_n_thds
8   0       198920       163820       8       138955       6       119703         5        1        24865           56             19  512   1  0.867         6526       0         4008       0           96        26995       1           10990       0               0       0               0       0            1226       0               0         0               0           0
16   1      1802688      1143707      56      1031039      50       221165        10        1       112668          563            309  256   1  0.781       105471       5        82548       4         1942        80503       3          191126       9               0       0              14       0            4316       0               0         0               0           0
32   2      9954560      1867465      91      1556385      76       267993        13        1       311080         2614            503  128   1  0.929       177825       8       136745       6         7713       176923       8          325128      15               2       0              52       0            8139       0               0         0               0           1
48   3     35382816      3763756     185      3026614     148       300952        14        1       737142         2953            220  256   3  0.975       371881      18       283650      13        12022        60637       2          667997      32               2       0              17       0            2725       0               0         0               0           1
......

“LOGGER_MEMCHECK_SAMPLE_NMD_INFO”与“LOGGER_MEMCHECK_DETIAL_INFO”均为进程jemalloc快照,区别在于:

  1. LOGGER_MEMCHECK_SAMPLE_NMD_INFO:单次维测连续采样2次,间隔为5分钟,内容包含size、allocated、nmalloc、ndalloc等四列内存申请相关信息;

  2. LOGGER_MEMCHECK_DETIAL_INFO:单次维测仅采样1次,内容包含进程jemalloc的完整信息。

[h2]内存栈

栈信息日志文件: memleak-native-[process_name]-[pid]-[timestamp].txt

[h2]native泄漏聚类规则

应用程序在同一或不同版本上、不同时间产生的泄漏问题可能为同一原因,开发者可以从故障日志中提取故障特征,根据故障特征将多份故障日志进行聚类,以提高泄漏问题的分析效率。

对于PSS_MEMORY故障,系统会发送两份故障日志给开发者进行分析,故障日志一(内存维测)用于存储进程的部分轻量化信息,如:smaps、ASHMEM、NMD等;故障日志二(内存栈)中用于存储系统检测到进程pss泄漏后抓取的栈信息。

  1. 对故障日志一中的进程“LOGGER_MEMCHECK_SMAPS_INFO”信息进行分析,根据以下表格所列方法计算各类型内存占比,筛选占比最高的内存泄漏类型。

    内存泄漏类型 计算方法
    虚拟机对象泄漏 搜索关键字“ArkTS”,计算“Pss”列和“SwapPss”列之和占总内存比例。
    堆内存泄漏 搜索关键字“jemalloc”,计算“Pss”列和“SwapPss”列之和占总内存比例。
    ASHMEM内存泄漏 搜索关键字“/dev/ashmem”,计算“Pss”列和“SwapPss”列之和占总内存比例。
    anon类型内存较大 搜索关键字“[anon]”,计算“Pss”列和“SwapPss”列之和占总内存比例。
    1. 每一行“Pss”列以及“SwapPss”列之和为对应内存块的申请大小。

    2. “Name”列为内存块的内存标签。

  2. 筛选出占比最高的内存泄漏类型后,可以根据以下规则进一步提取故障特征:

    • 虚拟机对象:筛选内存申请最大的内存标签作为故障特征,如:从以下日志中提取的故障标签为“[anon:ArkTS Heapsemi space]”。

      LOGGER_MEMCHECK_SMAPS_INFO
      -------------------------------[memory]-------------------------------
                                          Shared      Shared      Private     Private
      Size        Rss         Pss        Clean       Dirty         Clean       Dirty       Swap        SwapPss     Counts                 Name
      1662976     68744       68744       0           0           68744       0           0           0           525                     [anon:ArkTS Heap]
      
      5632        5600        2261        3452        0           2148        0           0           0           22                      [anon:ArkTS Heapappspawn space]
      
      98304       74012       74012       0           0           74012       0           0           0           307                     [anon:ArkTS Heapsemi space]
      
      ...
    • 堆内存:筛选内存申请最大的内存标签作为故障特征,如:从以下日志中提取的故障标签为“[anon:native_heap:jemalloc]”。

      LOGGER_MEMCHECK_SMAPS_INFO
      -------------------------------[memory]-------------------------------
                                          Shared      Shared      Private     Private
      Size        Rss         Pss        Clean       Dirty         Clean       Dirty       Swap        SwapPss     Counts                 Name
      327168      171464      146921      25416       0           146048      0           0           0           17                      [anon:native_heap:jemalloc]
      24600       3924        3586        348         0           3576        0           0           0           18                      [anon:native_heap:jemalloc meta]

      如果存在内存调用栈,可以根据NMD维测找到占用最高的内存区间,并结合抓取的调用栈维测聚类到具体代码段或者so作为怀疑点,具体分析方法可参考运维态高效处理Native泄漏。

    • ASHMEM内存:参考ASHMEM聚类规则。

    • anon内存:筛选内存申请最大的内存标签作为故障特征,如:从以下日志中提取的故障标签为“[anon]”。

      LOGGER_MEMCHECK_SMAPS_INFO
      -------------------------------[memory]-------------------------------
                                          Shared      Shared      Private     Private
      Size        Rss         Pss        Clean       Dirty         Clean       Dirty       Swap        SwapPss     Counts                 Name
      38760       528         524         4           0           524         0           0           0           56                      [anon]

      如果存在内存调用栈,可通过分析调用栈中占比较高的聚类到具体代码段或者so作为怀疑点,具体分析方法可参考运维态高效处理Native泄漏。

    对于nolog版本,默认不开启抓栈,因此推荐开发者根据smaps信息对PSS内存占用的类型进行初步聚类。

ASHMEM/DMA/GPU/GPU_RS内存泄漏日志规格

[h2]内存采样

[h2]内存维测

日志文件:memleak-kernel-[module]-0-[timestamp].txt (方式一)

字段 说明
LOGGER_MEMCHECK_MEMINFO 整机内存信息概览。
LOGGER_MEMCHECK_PROC_INFO ASHMEM/DMA(ION)/GPU对应泄漏内存节点信息打印(泄漏类型不同,落盘内容不同)。
LOGGER_PROCESS_DMABUF_INFO DMA(ION)内存泄漏时获取的特殊节点内容,包含更多的内存块使用信息。
LOGGER_MEMCHECK_RENDER_SERVICE_MEM Render_service进程的内存使用情况。

检测到ASHMEM/GPU/DMA(ION)内存泄漏时,会抓取整机ASHMEM/GPU/DMA(ION)内存信息,ASHMEM/DMA(ION)与句柄泄漏ASHMEM/DMA(ION)日志规格相同,参考ASHMEM/DMA(ION)类型句柄。

日志抬头:

Generated by HiviewDFX @HarmonyOS
LOGGER_MEMCHECK_GERNAL_INFO
memoryName:ion
softThreshold:2800(MB)
hardThreshold:4200(MB)
appHardThreshold:4096(MB)
topMemory:0(KB)

*****************************
LOGGER_MEMCHECK_MEMINFO
MemTotal:       11738500 kB
MemFree:          116204 kB
MemAvailable:      95232 kB
Buffers:               0 kB

日志文件内“LOGGER_MEMCHECK_PROC_INFO”会根据内存泄漏类型不同,落盘对应的内存信息,具体如下:

字段 说明
Process 持有DMA(ION)内存块的应用进程包名(16个字符截断)。
pid 发生故障进程pid。
fd 进程持有的句柄。
size_bytes 进程持有的DMA(ION)内存buffer大小,单位:B。
ino 文件inode号(索引节点号)。
exp_pid 从内核申请DMA(ION)内存的进程pid。
exp_task_comm 从内核申请DMA(ION)内存的进程名。
buf_name DMA(ION)内存的buffer名字。
exp_name DMA(ION)内存的buffer扩展名。
buf_type DMA(ION)内存的buffer类型。
leak_type DMA(ION)内存泄漏维测的buffer类型。

开发者可以参考DMA内存基础日志分析方法初步定位DMA内存泄漏问题。

  1. GPU_RS内存泄漏与GPU泄漏的区别在于:GPU是应用自渲染发生的泄漏,GPU_RS是通过进程render_service进行统一渲染发生的泄漏。

  2. 当前日志规格不代表维测的最终形态,后续会根据版本问题以及用户原声增加维测信息,变更形式包括但不限于行、列、段落等。

[h2]内存栈

从HarmonyOS 6.0.0开始,支持抓取GPU内存申请的调用栈以分析进程DMA(ION)泄漏问题。检测到泄漏后会收集15分钟内的GPU内存申请trace,开发者可本地搭建Smartperf环境并导入Profiler日志进行解析。

日志文件名称:memleak-kernel-[module]-[pid]-[timestamp].txt

[h2]ASHMEM/DMA/GPU/GPU_RS聚类规则

应用程序在同一或不同版本上、不同时间产生的泄漏问题可能为同一原因,开发者可以从故障日志中提取故障特征,根据故障特征将多份故障日志进行聚类,以提高泄漏问题的分析效率。

ASHMEM聚类规则

  1. 提取故障日志中的ASHMEM维测信息进行聚类,如下:

    Process_name    Process_ID      Fd      Cnode_idx       Applicant_Pid   Ashmem_name                     Virtual_size    Physical_size  magic
    XXXXX           816             22      328234          816             dev/ashmem/PolicyVolumeMap      541             4096            7
    XXXXX           816             22      328234          816             dev/ashmem/PolicyVolumeMap      541             4096            7
    XXXXX           816             22      328234          816             dev/ashmem/inputBuffer          541             1024            7
    XXXXX           816             22      328234          816             dev/ashmem/outputBuffer         541             512             7
    ......
  2. 分析ASHMEM维测中的“Ashmem_name”字段,来确认是否为同一类型的buffer泄漏,并将“Physical_size”列之和占比最高的buffer作为本次故障的故障特征。

DMA聚类规则

  1. 提取故障日志中的DMA(ION)维测信息来进行聚类,如下:

    *****************************
    LOGGER_MEMCHECK_PROC_INFO
    MM_DMABUF_INFO
    Process     pid      fd         size_bytes    ino        exp_pid      exp_task_comm    buf_name                                                                         exp_name           buf_type    leak_type
    process1    65141    246        278528        432510     42829        allocator_host    65141                                                                           mm_heap_helpers    NULL        NULL
    process1    65141    247        266240        434225     42829        allocator_host    65141                                                                           mm_heap_helpers    NULL        NULL
    process1    65141    248        274432        430933     42829        allocator_host    65141                                                                           mm_heap_helpers    NULL        NULL
    process1    65141    264        14036992      432500     42829        allocator_host    https://xxxx/xxxxx.png                                                          mm_heap_helpers    pixelmap    pixelmap
    process1    65141    266        14036992      426988     42829        allocator_host    https://xxxx/xxxxx.png                                                          mm_heap_helpers    pixelmap    pixelmap
    process1    65141    268        14036992      430936     42829        allocator_host    https://xxxx/xxxxx.png                                                          mm_heap_helpers    pixelmap    pixelmap
    process1    65141    258        4493312       432499     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    process1    65141    260        4493312       426987     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    process1    65141    262        4493312       431689     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    process1    65141    254        4493312       430935     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    process1    65141    256        4493312       431688     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    process1    65141    250        4493312       432498     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    process1    65141    252        4493312       430934     42829        allocator_host    srcImageSize-2160x2880-pixelMapSize-2160x2880-streamsize-761322-mimetype-webp   mm_heap_helpers    NULL        NULL
    ************ endl ************
  2. 根据“leak_type”和“buf_name”对buffer进行分类,提取出“size_bytes”之和占比最高buffer的“buf_name”作为本次故障的故障特征。分析细节可参考DMA泄漏分析方法。

    如果“leak_type”为NULL,可能存在多种类型的buffer,可以直接通过“buf_name”进行区分。

GPU/GPU_RS聚类规则

  1. 解析故障日志中提供的GPU维测信息,统计包含“Total memory:”字段的行并解析出对应类型GPU内存的占用,筛选占用最高的GPU内存类型作为故障特征。如以下维测中,“host default memory”类型的GPU内存占用为“1789351”字节,可以作为故障特征进行聚类:

    C: cq memory(not in total memory) (Total memory: 4096)
    13:                    1 / 4096
    
    C: vulkan external memory(not in total memory) (Total memory: 0)
    (empty)
    
    C: host default memory (Total memory: 1789351)
      5:                  269 / 4304
      6:                  370 / 15792
      7:                  401 / 33088
      8:                   96 / 14240
      9:                  449 / 141696
      10:                  265 / 173143
      11:                  172 / 236391
      12:                   68 / 187012
      13:                   35 / 197576
      14:                   17 / 251573
      15:                    6 / 108304
      16:                    1 / 51736
      17:                    1 / 84184
      19:                    1 / 290312
  2. 聚类到GPU内存类型后,筛选出其中占用最大的内存段并进行聚类。

不同的芯片平台中,GPU表现形式会存在差异:

C: host default memory (Total memory: 1789351)。

Channel: Texture (Total memory: 1789351)。

内核管控日志规格

触发内核管控时,系统资源供给已不足以支撑抓取开销较大的维测,因此只能提供基础维测信息支撑初步定界定位。

内核管控日志通用内容如下:

字段 说明
pidNumber 泄漏应用pid。
processName 泄漏应用进程名。
killTime 应用被查杀时间。
RssMemory 泄漏应用RSS内存占用,单位:KB。
killReason 应用被查杀原因。
Generated by HiviewDFX @HarmonyOS
LOGGER_MEMCHECK_GERNAL_INFO
 pidNumber: 2017
 processName: process1
 killTime: 20260512090030
 killReason: RssThresholdKiller
 RssMemory: 8350500

“RssMemory”是应用触发RSS内核管控后日志中展示的RSS总内存大小。同理,“GpuMemory”、“IonMemory”、“AshmemMemory”为各内核管控日志中展示的内存大小。

[h2]RSS内核管控

概述:应用RSS内存泄漏超过整机运行内存的1/3,且整机处于低内存状态时,触发RSS内核管控。

日志文件:memleak-kernel-[module]-0-[timestamp].txt(方式一)或 RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

RSS内核管控日志内容如下:

字段 说明
LOGGER_MEMCHECK_SAMPLIFY_SMAPS_INFO 记录了该进程的smaps汇总信息。
Size 应用申请内存块的虚拟内存大小,单位:KB。
Rss 应用申请内存块的物理内存大小,单位:KB。
Swap 应用申请后暂不使用,被换到SWAP分区的的物理内存大小,单位:KB。
Name 应用申请的内存标签。
LOGGER_MEMCHECK_SAMPLIFY_SMAPS_INFO
    Size         Rss        Swap    Name
     256           4           0    [anon:ark-Object Space]
     256         240           0    [anon:ark-Non Movable Space]
     256          48           0    [anon:ark-Object Space]
  523520           4           0    [anon]
  783104           0           0    [anon:ArkTS Heap]
     256         144          16    [anon:ArkTS Heapnon movable space]
     256           8           0    [anon:ArkTS Heapread only space]
     256          32           0    [anon:ArkTS Heapshared non movable space]
     256          48           0    [anon:ArkTS Heapshared read only space]
     256         136          60    [anon:ArkTS Heapnon movable space]
  524288           0           0    [anon:ArkTS Heap]
     256          32           0    [anon:ArkTS Heapappspawn space]
     256         240          16    [anon:ArkTS Heapsemi space]
......

开发者可以根据"Rss"列的内存之和计算出进程的RSS内存总占用。

[h2]GPU内核管控

概述:应用GPU内存泄漏超过整机运行内存的1/3,且整机处于低内存状态时,触发GPU内核管控。

日志文件:memleak-kernel-[module]-0-[timestamp].txt(方式一)或 RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

GPU内核管控日志内容与GPU内存泄漏日志规格中的“LOGGER_MEMCHECK_PROC_INFO”字段下的维测内容保持一致。

[h2]ASHMEM内核管控

概述:应用ASHMEM内存泄漏超过整机运行内存的1/3,且整机处于低内存状态时,触发ASHMEM内核管控。

日志文件:memleak-kernel-[module]-0-[timestamp].txt(方式一)或 RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

ASHMEM内核管控日志内容与ASHMEM内存泄漏日志规格中的“LOGGER_MEMCHECK_PROC_INFO”字段下的维测内容保持一致。

[h2]DMA内核管控

概述:应用DMA(ION)内存泄漏超过整机运行内存的1/3,且整机处于低内存状态时,触发DMA(ION)内核管控。

日志文件:memleak-kernel-[module]-0-[timestamp].txt(方式一)或 RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

DMA(ION)内核管控日志内容与DMA内存泄漏日志规格中的“LOGGER_MEMCHECK_PROC_INFO”字段下的维测内容保持一致。

[h2]thread内核管控

概述:应用申请线程过多,导致整机调度不足时,会触发thread内核管控。

日志文件:threadleak-#{module}-#{pid}-log-#{timestamp}.txt(方式一)或 RESOURCE_OVERLIMIT_[TIMESTAMP]_[PID].log(方式三)。

thread内核管控日志内容如下:

字段 说明
pidNumber 泄漏应用pid。
processName 泄漏应用进程名。
killTime 应用被查杀时间。
foreGround 应用前后台状态,yes为前台,no为后台。
killReason 应用被查杀原因。
threadCount 应用创建线程总数。
Generated by HiviewDFX @HarmonyOS
LOGGER_MEMCHECK_GERNAL_INFO
 pidNumber : 8387
 processName : process1
 killTime : 20260512090030
 foreGround : no
 killReason : ThreadKiller
 threadCount : 3001

the process is killed by runnable thread threshold 3001 / 4124.
Thread_process1:2099
Thread_HI:9
Thread_GI:9
Thread_FI:9
Thread_DI:9
Thread_BI:9
Thread_EI:9
Thread_AI:9
Thread_CI:9
......
  1. 日志中展示了按照线程名聚类后,top10数量的线程,如“Thread_process1”、“Thread_HI”等。“Thread_process1:2099” 表示线程“Thread_process1”的数量为“2099”个。

  2. "the process is killed by runnable thread threshold 3001 / 4124." 表示应用被杀时总线程数为4124个,处于running和runnable状态的线程总和为3001个。