当前位置: 首页 > news >正文

APP 内存测试--Android Profiler实操(入门版)

背景: app内存测试我们一般关注内存抖动和内存泄漏方面的问题

一、APP内存测试

1.1 内存抖动

        内存抖动的产生原因是短时间内有大量的内存申请和释放,造成了内存抖动厉害。内存抖动最直接的影响是可能会造成app使用过程中的卡顿,因为内存抖动伴随着大量的GC,现在的机制GC是会造成短暂的停顿。

1.2 内存泄露

        Android内存在分配之后,由于被生命周期比它长的对象引用造成在使用完之后也无法释放。

1.3 Android Profiler介绍

        Android Profiler的Memory Profiler组件, 可用于帮助我们分析内存泄露和内存抖动的问题。Memory Profiler的功能包括:  展示应用内存使用情况的实时图像、抓取内存的dump信息、强制垃圾回收及追踪内存分配。

二、环境准备

 2.1  将手机通过USB链接至电脑,连接时需要确认手机是处于“USB调试”模式
 2.2   打开AndroidStudio,从底部的控制台选择Android Profiler

如果底部没有Android Profiler选项,可以从顶部工具栏 View—Tool Windows—Profiler

3、在Android Profiler中,点击SESSIONS后方的“+”,然后选择已连接的设备及自己要测试的APP的进程名,如【com.xxxx.xxx】。

4、点击后如下图,我们可以看到Android Profiler分为四大模块: CPU、内存 、网络、能耗:

5、单击MEMORY时间轴中的任意位置打开MEMORY Profiler,如下图所示;点击旁边箭头可返回上一级页面

三、通用测试步骤

      1. 进入某一个页面,滑动页面,多滑几次,然后退出页面,进行GC。
      2.进入某一页面,操作一些界面元素,比如加载更多元素、删除某个元素、增加某个元素等。
      3. 进入某一个页面,接收和处理大量网络数据的场景,比如下载大量的图片等。
      4.对于新增模块,比较和上个版本的内存值,内存增加是否符合预期。
      5.APP启动过程中(热启动、冷启动、首次启动),内存的变化情况。

Memory Profiler界面按钮说明: 如下图

标注①按键:用于强制内存回收。

标注②按键:用于抓取进程内存的dump信息。

标注③按键:用于记录内存的分配信息。  初次点击Record native allocations时,对应统计的开始时间点;再次点击时,对应统计的结束时间点。进程在两个时间点之间的内存分配信息,将被Memory Profiler记录和分析。

标注④区域:用于缩放/复原时间轴。

标注⑤按键:用于显示/停止显示实时的内存数据。

标注⑥区域:用于记录事件发生的时间点及大致持续的时间(例如点击事件、返回事件、屏幕旋转事件等事件)。

Memory Profiler统计内存种类及其含义

Total:表示app独自占用内存,后面几项之和;

Java:表示Java代码或Kotlin代码分配的内存;

Native:表示C或C++代码分配的内存(即使App没有native层,调用framework代码时,也有可能触发分配native内存);

Graphics:表示图像相关缓存队列占用的内存;

Stack:表示native和java占用的栈内存;

Code:表示代码、资源文件、库文件等占用的内存;

Others:表示无法明确分类的内存;

Allocated:表示Java或Kotlin分配对象的数量。

四、基本用法

4.1 查看内存分配情况

Memory Profiler可以查看两个时间点之间的内存分配情况

4.1.1  点击内存统计任意区域,会显示两条线,拖拽任意一条线,即可以选择观察区域;

4.1.2  选定观察区域后, 下方Table区域就可以统计这段时间内分配对象的类名;

4.1.3  因为类比较多,我们可以在搜索框,输入关键字(比如:cert),找到我们想要关注的类(可以与开发沟通)后,点击该类,然后会在右侧Instance View显示具体的对象; 

4.1.4  点击具体对象后,会在Allocation Call Stack区域显示调用栈。点击调用栈信息后,就会跳转到具体的代码(前提是你本地有代码)。

Allocations :表示实例数量

Shallow Size:表示对象使用Java内存的大小,单位为byte; 

4.2 查看内存占用情况

4.2.1 在Memory Profiler界面点击Dump Java heap按钮,抓取点击后一段时间内app占用内存的dump信息(文件比较大)。

4.2.2  抓取后会自动显示dump信息,我们可以通过搜索框,搜索我们想要关注的类(如:cert);

4.2.3 点击类后,会在下方Instance显示具体的对象;

4.2.4 点击具体的对象后,会在右侧显示详细信息;

Depth:表示当前对象到任一GC root的最短跳数;

Native Size:表示类对象所引用的Native对象所消耗的内存的大小;

Shallow Size:表示对象使用Java内存的大小,单位为byte; 

Retained Size:表示对象占用的实际内存大小,大于等于Shallow Size;

五、测试结果分析

 5.1 内存抖动

        如果在很短的时间内发生了多次的内存申请和释放,有多处高峰值,虽然也有回收操作,但是尖峰值过多,垃圾回收站频繁操作,导致短时间内执行了多次GC操作。出现这种现象的时候,明显能感觉到App的卡顿,甚至出现应用进程被干掉,这种现象则可判断为此操作中存在内存抖动现象。

5.2 内存泄漏

        内存泄露时 Memory Profiler 会呈现一个类似阶梯型的内存上升趋势

六、测试标准

 6.1 内存抖动
          10s内出现 大于等于 4次的内存波动(图形上有4个毛刺),如下图即为不通过。

 6.2  内存泄露
        理论上不能有任何的内存泄露。

七、dumpsys meminfo

    命令行方式查看内存情况

   查看设备内存使用情况:adb shell cat /proc/meminfo

7.1  App运行内存

我们目前主要关注两方面的运行内存:app启动内存平均值、app运行主要功能之后的内存平均值

查看某APP应用内存使用信息:adb shell dumpsys meminfo com.xxxx.xxx(待测应用包名)

属性说明1:

Uptime:表示启动到现在的时长,不包含休眠的时间,单位毫秒(ms)

Native Heap:由C/C++申请的内存空间在native heap

Dalvik Heap:由java对象申请的对象,全部都在Dalvik Heap,我们通常关注一个app的内存是Dalvik Heap。

Dalvik Other:类数据结构和索引占据的内存

Stack:栈内存

Unknown:无法归类到上面提到的内存类型中,除此之外的内存。

TOTAL:各个项占用的内存的总值。

Pss total(Proportional set Size 按比例分配占用内存):实际使用内存

Private Dirty & Clean:指的是进程独占内存。通常我们更关注Private dirty内存,因为这部分内存是在应用退出之后,可以被回收的内存。换句话说,这部分内存是应用 new 出来的对象实例。

 SwapPss Dirty:用于监视系统中内存交换操作的情况

Heap size:虚拟机Heap 的大小,指占用总内存(Heap  堆)

Heap Alloc : 统计的是虚拟机分配的所有应用实的内存大小

Heap Free: 虚拟机当前可用的Heap大小(空闲内存)。

属性说明2:

说明:

Graphics:为图形的内存使用情况

Total PSS:上下两部分其实是对此应用使用内存量做了不同分类,值是相同的,都是75685

Objects:表示该app的一些对象的数量,例如view控件存在44个,Activity分配的内存有1个

SQL & DATABASES:是app操作过程中数据库相关的内存情况

Asset Allocations : 这里是将asset下面文件解压之后,放到内存中。

7.2  结果分析

 7.2.1 建议App占用内存采用 Pss Total 的值。(因为这个是app 进程真实占用的内存值)。  

  至于Heap Size、Heap Alloc、Heap Free是Dalvik所分配的堆大小(反映了java代码分配的内存,但是也会包含Zygote共享的内存)

7.2.2 建议采集3到5次的内存数据,求平均值。

7.2.3  对前后两个版本的内存(或者三个版本)进行数据对比。

八、 其他说明

Android系统对dalvik的vm heapsize作了硬性限制,当java进程申请的java空间超过阈值时,就会抛出OOM异常(这个阈值视机型而定)

  查看单个应用最大内存限制,我们可以在shell中输入命令:getprop|grep heapgrowthlimit 

可以看到我的测试机(荣耀Magic3)的限制为384M,dalvik process 超过就会抛OOM异常

http://www.lryc.cn/news/577263.html

相关文章:

  • Unity编辑器扩展之扫描项目中所有图片资源,并找出引用这些图片的预制体及其引用路径,最终导出为CSV报告
  • Monorepo+Pnpm+Turborepo
  • Windows 安装 nodejs npm
  • 网络拓扑图绘制全流程:从架构解析到工具实战
  • Jenkins Pipeline 实战指南
  • Java基础(六):数组全面解析
  • python+uniapp基于微信小程序的生鲜订购系统nodejs+java
  • Java 图书管理系统
  • 在拉卡拉分账功能中实现实时更新,需结合异步回调通知和数据库事务来确保数据一致性。以下是具体实现方案
  • 【Linux系统部分】在Linux命令行中写一个简单的shell外壳
  • 网络安全2023—新安全新发展
  • HarmonyOS NEXT仓颉开发语言实战案例:电影App
  • 【AI时代速通QT】第四节:Windows下Qt Creator调试指南
  • Oracle 进阶语法实战:从多维分析到数据清洗的深度应用​(第四课)
  • ChatGPT、DeepSeek等大语言模型助力高效办公、论文与项目撰写、数据分析、机器学习与深度学习建模等科研应用
  • SQL参数化查询:防注入与计划缓存的双重优势
  • 高性能MySQL集群:架构设计与优化实战指南
  • 银河麒麟系统上利用WPS的SDK进行WORD的二次开发
  • 【Oracle学习笔记】7.存储过程(Stored Procedure)
  • jvm的调优命令jstack打印堆栈信息阐述以及调优
  • 04_Americanas精益管理项目_数仓搭建
  • VMware vSphere 9与ESXi 9正式发布:云原生与AI驱动的虚拟化平台革新
  • QT控件 使用Font Awesome开源图标库修改QWidget和QML两种界面框架的控件图标
  • Maven 中,dependencies 和 dependencyManagement
  • 基于C++实现 bp 神经网络的手写数字识别
  • 【LeetCode 热题 100】239. 滑动窗口最大值——(解法一)滑动窗口+暴力解
  • 从0开始学习计算机视觉--Day06--反向传播算法
  • 【FR801xH】富芮坤FR801xH之PMU GPIO
  • Stable Diffusion 项目实战落地:从0到1 掌握ControlNet 第三篇: 打造光影字形的创意秘技-文字与自然共舞
  • [面试] js手写题-树转数组