Android 内存指标与分析方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 内存指标与分析方法相关的知识,希望对你有一定的参考价值。

参考技术A

这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~

这篇文章偏底层,难免有写错的地方还请你多多斧正哦~

android 系统包括三种不同类型的内存:RAM、zRAM 和 ROM:

对于内核来说,无论是内核进程还是用户进程,说到底都是 task_struct 结构体的一个实例。task_struct 也叫进程描述符(process descriptor),里面记录了进程相关的所有信息。

在 task_struct 中有一个 mm_struct 的数据结构,也叫内存描述符(memory descriptor),里面记录了 Linux 进程内存管理的所有信息。mm_struct 定义在 linux/mm_types.h 头文件中,其中有一个页(page)的数据结构:

—— 图片引用自网络

页(Page)是 Linux 内核进行内存管理的基本单位,通常一个页的大小为 4 KB 。根据页面是否使用分为 “可用页” 和 “已使用页” 两种,其中已使用页可以分为以下类别:

缓存页是指有存储器中的文件支持的内存,分为两种: 私有页 & 共享页

匿名页是没有存储器中的文件支持的内存(例如由设置了 MAP_ANONYMOUS 标志的 mmap() 进行分配)

为了避免应用滥用内存,Android 系统会限制应用可以申请的最大堆内存,超过此限制就会抛出 OOM 异常。Android 设备出厂后,最大堆内存就已经确定,相关的配置位于系统根目录 /system/build.prop 文件中,我们可以通过命令查看:

在 App 虚拟机启动时,会读取 /system/build.prop 文件的配置,源码位于: AndroidRuntime.cpp

需要注意的是,配置 dalvik.vm.heapgrowthlimit 限制的仅仅是 Java 堆内存,本地内存不受其限制的。换句话说,应用可以使用的最大内存其实是可以大于最大堆内存的。

在确定进程占用了多少内存时,必须考虑多个进程共享页的情况。在 Linux 里,一个进程占用的内存有四种指标,分别是:

一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS。

—— 图片引用自 https://developer.android.google.cn/topic/performance/memory-management Android Developers

—— 图片引用自 https://www.cnblogs.com/sunsky303/p/13494977.html —— sunsky303 著

关于输出信息的具体分析,建议直接看 Gityuan 的这篇文章: 《Android 内存分析命令》 ,已经写得非常详细了。

Android客户端性能测试—内存先码

前言:

1.该内容为APP应用客户端的性能测试,未涉及后台,所以并非针对API或数据接口

2.测试的目标项:资源消耗、内存泄露、电量功耗、响应时间

3.客户端的性能指标:内存、CPU、流量

4.本系列主要是讲述 如何获取安卓APP应用的性能指标,并简单分析,定位问题

 

一、查看 内存 指标:

准备工作:

(1).进入装有测试APP手机的 “开发人员选项” 并打开“USB调试模式”

(2).使用数据线将手机设备与电脑设备连接,可装PP助手进行接入

(3).手机打开待测APP,即打开进程

 

1.命令行查看内存数据:

(1).打开cmd

 

(2). 获取设备列表:输入 adb devices(预先安装adb驱动、若报错,拔掉重新连接手机)

 技术分享图片

(3).进入该设备的shell环境:输入:adb -s 0815f8a3024a2605 shell  (若只有一台设备,可直接 adb shell ,多台必须加设备序列号0815f8a3024a2605)

 技术分享图片

(4).查找进程:输入ps (模糊查找)    寻找对应待测应用包名,并记录下其的pid(进程ID):20852,

若知道明确的包名,可直接准确查找 ps |grep com.quncao.lark

 技术分享图片

(5).查询内存信息:

可通过两种方式获取:

a.通过 “ dumpsys meminfo  包名/pid ” 命令获取,输入:dumpsys meminfo 20852

技术分享图片

Pss Total :实际使用的物理内存

private dirty:私有驻留内存

Heap Size:    占用总内存(Heap  堆)(扩展:进程内存空间是虚拟内存,区分于物理内存,进程无法直接操作物理内存RAM。必要时,操作系统对其进行映射,使进程能应用到物理内存)

Heap Alloc:   分配内存

Heap Free:   空闲内存

native process和java process占据内存的大小(扩展:c++申请的内存为native process,java申请的内存:java process)

内存大小:native process:13004

                    dalvik process:10448

注:因为Android系统对dalvik的vm heapsize作了硬性限制,当java进程申请的java空间超过阈值时,就会抛出OOM异常(这个阈值可以是48M、24M、16M等,视机型而定)

查看单个应用最大内存限制,输入命令:getprop|grep heapgrowthlimit  得到结果该机型为192M。dalvik process 超过就会抛OOM异常

 技术分享图片

b.可直接通过:procrank 。

手机中的sh是经过精简过的,有些手机可能没有 procrank 命令,可以使用genymotion模拟器,或是自己安装procrank命令。

(我也没这个命令,没有装好,这部分内容未操作,为网络直接获取)

 技术分享图片

VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)——是单个进程全部可访问的地址空间

RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)——单个进程实际占用的内存大小,不是精确描述

PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)——对于系统中的整体内存使用是一个很好的描述

USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)——单个进程的全部私有内存大小,亦即全部被该进程独占的内存大小。

一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS。

 

USS 是针对某个进程开始有可疑内存泄露的情况,进行检测的最佳数字

 

2.代码获取内存数据:

java调用Adb shell dumpsys meminfo再用字符串截取方式获取内存,可对其数据进行返回打印,实现监控。

传入参数为:应用包名,这个不可变。

 1 package com.hss.performanceTest;
 2 /**
 3  * from hss
 4  * data:2017/9/8
 5  * project:getMemory
 6  */
 7 import java.io.BufferedReader;
 8 import java.io.IOException;
 9 import java.io.InputStreamReader;
10  
11 public class getMemory {
12  
13     public static String GetMemory(String packageName) throws IOException, InterruptedException {
14  
15         String str3=null;
16           Runtime runtime = Runtime.getRuntime();
17           Process proc = runtime.exec("adb shell dumpsys meminfo "+packageName);
18           try {
19  
20               if (proc.waitFor() != 0) {
21                   System.err.println("exit value = " + proc.exitValue());
22               }
23               BufferedReader in = new BufferedReader(new InputStreamReader(
24                       proc.getInputStream()));
25               StringBuffer stringBuffer = new StringBuffer();
26               String line = null;
27               while ((line = in.readLine()) != null) {
28                   stringBuffer.append(line+" ");
29  
30               }
31               String str1=stringBuffer.toString();
32               String str2=str1.substring(str1.indexOf("Objects")-60,str1.indexOf("Objects"));     
33               str3=str2.substring(0,10);
34               str3.trim();
35           } catch (InterruptedException e) {
36               System.err.println(e);
37           }finally{
38               try {
39                   proc.destroy();
40               } catch (Exception e2) {
41               }
42           }
43         return str3 ;
44     }
45     public static void main(String args[]) {
46         
47         System.out.println("开始运行...");
48         try {
49             String resurt = getMemory.GetMemory("com.hundsun.stockwinner.sxzq");
50             System.out.println("山西证券的内存:"+resurt);
51         } catch (IOException e) {
52             // TODO Auto-generated catch block
53             e.printStackTrace();
54         } catch (InterruptedException e) {
55             // TODO Auto-generated catch block
56             e.printStackTrace();
57         }             
58     } 
59     
60 }

 

运行截图:

 技术分享图片

以上是关于Android 内存指标与分析方法的主要内容,如果未能解决你的问题,请参考以下文章

mysql性能瓶颈分析性能指标指标搜集方法与性能分析调优工具

JVM内存管理概述与android内存泄露分析

mysql的性能瓶颈分析性能指标性能指标信息的搜集工具与方法分析调优工具的使用

Android常见内存泄露分析及MAT与Profiler内存分析时间

数据采集与分析的指标都有哪些

Android App性能优化——内存CPU耗电量启动时间指标获取