• Profiler内存泄露实际案例分析


    前言

    本篇文章,将以一个实际案例为基础,从分析问题表象出发,在借助Profiler的情况下,教你如何一步一步剖析和解决问题。


    案例

    最近测试那边反馈了一个系统卡顿的问题
    出现的场景,是在安卓设备(手机)运行一段时间后,会变得很卡顿。


    分析一

    系统出现卡顿,我们一般会从2个角度,切入分析:

    1. CPU占用率。
    2. 内存占用率。

    • CPU占用率分析

    通过adb shell top命令,我们可以看到当前cpu占用率,以及每个进程的占用率,如下图所示:
    在这里插入图片描述
    这里面总的可用CPU可用率为800%,user进程占用100%,system进程占用291%空闲有391%。相当于,CPU空闲率几乎接近50%。由此,可以排除CPU占用率高的问题。

    • 内存占用率分析
      通过adb shell dumpsys meminfo命令,我们可以查看各个进程对内存的占用率,以及剩余可用的内存空间,如下图所示:
      在这里插入图片描述
      图1展示了各进程的内存占用率

    在这里插入图片描述

    图2展示了当前设备的内存占用率

    这里的图1、图2,只是示例图,非当时案发现场的内存占用率。当时测试人员,测出系统卡顿时,中心服务的进程内存占用高达1.4+GBFree RAM,所剩无几。由此,可以初步判断,是中心服务进程内存占用过高,拖慢了整个系统,导致系统卡顿。

    分析二

    基于分析一的情况,接下来,我们借助Android Studio的Profiler工具对中心服务进程的内存占用,进行监控,如下图所示:
    在这里插入图片描述
    这里我放着煲机,煲了有十几分钟,通过图片,我们可以明显发现,随着时间的推移,Native层的内存占用率越来越高。

    由此,我们可以进一步猜测,是底层代码没有释放相关的内存资源。此时,我们可以通过左边控制面板,通过选中Record nativ allocations,并点击Record按钮,进行内存分配的监控。监控时长,视内存飙升的速度而定,飙升的越高,监控时长可以越短。监控完,点击stop即可。

    这里以60s为例,识别结果如下图所示:
    在这里插入图片描述
    通过图片的调用栈关系,我们可以看出是由中心服务进程中的语音模块,有个ZoneRecorder类,该类的runAudioRecorder方法,调用了jni层native-lib.cpp的代码。

    最终触发,这个底层方法:JNIEnv::GetByteArrayElements(),这个方法在不断的吃内存。

    随着监控时间变长,这个方法所占用的内存也会变大。

    由此,我们已经找出了内存泄露的地方,通过注释掉ZoneRecorder.runAudioRecorder方法的实现,屏蔽掉JNI层的调用后,再重新运行中心服务,可以发现,native层的内存占用,会一直维持在一个较低且非常稳定的范围值之内。


    总结,当出一个问题时,我们不能简单的惑于表面,就下判断。比如,出现系统卡顿时,不能第一时间就下定论说是系统的问题,然后就丢给系统人员。

    应该抱持科学严谨的态度,对内存分配进行层层追踪,以事实为依据,下的定论,才能更让人信服。

  • 相关阅读:
    AUTOSAR汽车电子嵌入式编程精讲300篇-车载网络 CAN 总线报文异常检测
    深度学习——池化层笔记+代码
    flink入门介绍
    工程水文学知识点
    Java随记 —— Servlet 教程笔记
    【QML】vscode安装QML格式化插件方法
    基于Apache Hudi 构建Serverless实时分析平台
    基于matlab的图像二维小波分解算法仿真
    华为OD机试真题 Java 实现【比赛的冠亚季军】【2023 B卷 100分】,附详细解题思路
    java下载文件成word
  • 原文地址:https://blog.csdn.net/l_o_s/article/details/126546415