Android4.4 meminfo 实现分析
2015-12-15 16:21
162 查看
Android 4.4 meminfo 实现分析
Posted byRoger
on 2014 年 3 月 24 日
Android提供了一个名为meminfo的小工具帮助应用分析自身的内存占用,并且在4.4还新增了memtrack HAL模块,SoC厂商通过实现memtrack模块,让meminfo可以获取GPU相关的一些内存分配状况。了解meminfo的实现,对我们更深入了解应用的内存占用状况是很有帮助的。而这篇文章的目的就是分析Android 4.4 meminfo的内部实现源码,让开发者通过这些信息可以更了解自己应用的内存占用状况。
在控制台输入命令”adb shell dumpsys meminfo YOUR-PACKAGE-NAME”,可以看到类似下图的结果:
C
** MEMINFO in pid 14120 [com.UCMobile.test] **
Pss Private Private Swapped Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 187886 187872 0 0 325232 174093 38594
Dalvik Heap 24801 24444 0 0 41476 35899 5577
Dalvik Other 700 700 0 0
Stack 508 508 0 0
Other dev 33564 32600 4 0
.so mmap 9019 1244 7268 0
.apk mmap 101 0 16 0
.ttf mmap 1330 0 696 0
.dex mmap 2248 0 2248 0
code mmap 985 0 188 0
image mmap 1182 908 12 0
Other mmap 130 4 108 0
Graphics 25504 25504 0 0
GL 2196 2196 0 0
Unknown 32476 32476 0 0
TOTAL 322630 308456 10540 0 366708 209992 44171
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ** MEMINFO in pid 14120 [com.UCMobile.test] ** Pss Private Private Swapped Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ Native Heap 187886 187872 0 0 325232 174093 38594 Dalvik Heap 24801 24444 0 0 41476 35899 5577 Dalvik Other 700 700 0 0 Stack 508 508 0 0 Other dev 33564 32600 4 0 .so mmap 9019 1244 7268 0 .apk mmap 101 0 16 0 .ttf mmap 1330 0 696 0 .dex mmap 2248 0 2248 0 code mmap 985 0 188 0 image mmap 1182 908 12 0 Other mmap 130 4 108 0 Graphics 25504 25504 0 0 GL 2196 2196 0 0 Unknown 32476 32476 0 0 TOTAL 322630 308456 10540 0 366708 209992 44171 |
C
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
stats_t stats[_NUM_HEAP];
memset(&stats, 0, sizeof(stats));
load_maps(pid, stats);
struct graphics_memory_pss graphics_mem;
if (read_memtrack_memory(pid, &graphics_mem) == 0) {
...
}
...
}
static void load_maps(int pid, stats_t* stats)
{
char tmp[128];
FILE *fp;
sprintf(tmp, "/proc/%d/smaps", pid);
fp = fopen(tmp, "r");
if (fp == 0) return;
read_mapinfo(fp, stats);
fclose(fp);
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, jint pid, jobject object) { stats_t stats[_NUM_HEAP]; memset(&stats, 0, sizeof(stats)); load_maps(pid, stats); struct graphics_memory_pss graphics_mem; if (read_memtrack_memory(pid, &graphics_mem) == 0) { ... } ... } static void load_maps(int pid, stats_t* stats) { char tmp[128]; FILE *fp; sprintf(tmp, "/proc/%d/smaps", pid); fp = fopen(tmp, "r"); if (fp == 0) return; read_mapinfo(fp, stats); fclose(fp); } |
C
80ff5000-810f2000 rw-p 00000000 00:00 0 [stack:12211]
Size: 1012 kB
Rss: 4 kB
Pss: 4 kB
...
81100000-811a4000 rw-s 000f4000 00:0b 6285 /dev/kgsl-3d0
Size: 656 kB
Rss: 652 kB
Pss: 352 kB
...
811d1000-811e0000 rw-p 00000000 00:00 0 [anon:libc_malloc]
Size: 60 kB
Rss: 60 kB
Pss: 60 kB
...
Name: [anon:libc_malloc]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 80ff5000-810f2000 rw-p 00000000 00:00 0 [stack:12211] Size: 1012 kB Rss: 4 kB Pss: 4 kB ... 81100000-811a4000 rw-s 000f4000 00:0b 6285 /dev/kgsl-3d0 Size: 656 kB Rss: 652 kB Pss: 352 kB ... 811d1000-811e0000 rw-p 00000000 00:00 0 [anon:libc_malloc] Size: 60 kB Rss: 60 kB Pss: 60 kB ... Name: [anon:libc_malloc] |
但是应用所使用的全部内存里面,有一些内存块是不映射到进程的userspace地址空间的(主要是GPU所使用的内存),这些内存块的信息在smaps里面无法找到,所以在Android 4.4里面新增了一个memtrack的HAL模块由SoC厂商实现,如果SoC厂商实现了memtrack模块,meminfo则可以通过libmemtrack的调用获取一些跟GPU相关的内存使用信息。所以我们看到android_os_Debug_getDirtyPagesPid方法通过调用read_memtrack_memory方法来读取Graphics,GL这两项的内存使用信息。
C
/*
* Uses libmemtrack to retrieve graphics memory that the process is using.
* Any graphics memory reported in /proc/pid/smaps is not included here.
*/
static int read_memtrack_memory(struct memtrack_proc* p, int pid,
struct graphics_memory_pss* graphics_mem)
{
int err = memtrack_proc_get(p, pid);
...
ssize_t pss = memtrack_proc_graphics_pss(p);
...
graphics_mem->graphics = pss / 1024;
pss = memtrack_proc_gl_pss(p);
...
graphics_mem->gl = pss / 1024;
pss = memtrack_proc_other_pss(p);
...
graphics_mem->other = pss / 1024;
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * Uses libmemtrack to retrieve graphics memory that the process is using. * Any graphics memory reported in /proc/pid/smaps is not included here. */ static int read_memtrack_memory(struct memtrack_proc* p, int pid, struct graphics_memory_pss* graphics_mem) { int err = memtrack_proc_get(p, pid); ... ssize_t pss = memtrack_proc_graphics_pss(p); ... graphics_mem->graphics = pss / 1024; pss = memtrack_proc_gl_pss(p); ... graphics_mem->gl = pss / 1024; pss = memtrack_proc_other_pss(p); ... graphics_mem->other = pss / 1024; return 0; } |
C
/*
* The Memory Tracker HAL is designed to return information about device-specific
* memory usage. The primary goal is to be able to track memory that is not
* trackable in any other way, for example texture memory that is allocated by
* a process, but not mapped in to that process' address space.
* A secondary goal is to be able to categorize memory used by a process into
* GL, graphics, etc. All memory sizes should be in real memory usage,
* accounting for stride, bit depth, rounding up to page size, etc.
*
* A process collecting memory statistics will call getMemory for each
* combination of pid and memory type. For each memory type that it recognizes
* the HAL should fill out an array of memtrack_record structures breaking
* down the statistics of that memory type as much as possible. For example,
* getMemory(, MEMTRACK_TYPE_GL) might return:
* { { 4096, ACCOUNTED | PRIVATE | SYSTEM },
* { 40960, UNACCOUNTED | PRIVATE | SYSTEM },
* { 8192, ACCOUNTED | PRIVATE | DEDICATED },
* { 8192, UNACCOUNTED | PRIVATE | DEDICATED } }
* If the HAL could not differentiate between SYSTEM and DEDICATED memory, it
* could return:
* { { 12288, ACCOUNTED | PRIVATE },
* { 49152, UNACCOUNTED | PRIVATE } }
*
* Memory should not overlap between types. For example, a graphics buffer
* that has been mapped into the GPU as a surface should show up when
* MEMTRACK_TYPE_GRAPHICS is requested, and not when MEMTRACK_TYPE_GL
* is requested.
*/
enum memtrack_type {
MEMTRACK_TYPE_OTHER = 0,
MEMTRACK_TYPE_GL = 1,
MEMTRACK_TYPE_GRAPHICS = 2,
MEMTRACK_TYPE_MULTIMEDIA = 3,
MEMTRACK_TYPE_CAMERA = 4,
MEMTRACK_NUM_TYPES,
};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* * The Memory Tracker HAL is designed to return information about device-specific * memory usage. The primary goal is to be able to track memory that is not * trackable in any other way, for example texture memory that is allocated by * a process, but not mapped in to that process' address space. * A secondary goal is to be able to categorize memory used by a process into * GL, graphics, etc. All memory sizes should be in real memory usage, * accounting for stride, bit depth, rounding up to page size, etc. * * A process collecting memory statistics will call getMemory for each * combination of pid and memory type. For each memory type that it recognizes * the HAL should fill out an array of memtrack_record structures breaking * down the statistics of that memory type as much as possible. For example, * getMemory(, MEMTRACK_TYPE_GL) might return: * { { 4096, ACCOUNTED | PRIVATE | SYSTEM }, * { 40960, UNACCOUNTED | PRIVATE | SYSTEM }, * { 8192, ACCOUNTED | PRIVATE | DEDICATED }, * { 8192, UNACCOUNTED | PRIVATE | DEDICATED } } * If the HAL could not differentiate between SYSTEM and DEDICATED memory, it * could return: * { { 12288, ACCOUNTED | PRIVATE }, * { 49152, UNACCOUNTED | PRIVATE } } * * Memory should not overlap between types. For example, a graphics buffer * that has been mapped into the GPU as a surface should show up when * MEMTRACK_TYPE_GRAPHICS is requested, and not when MEMTRACK_TYPE_GL * is requested. */ enum memtrack_type { MEMTRACK_TYPE_OTHER = 0, MEMTRACK_TYPE_GL = 1, MEMTRACK_TYPE_GRAPHICS = 2, MEMTRACK_TYPE_MULTIMEDIA = 3, MEMTRACK_TYPE_CAMERA = 4, MEMTRACK_NUM_TYPES, }; |
C
int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type,
struct memtrack_record *records,
size_t *num_records)
{
...
sprintf(tmp, "/d/kgsl/proc/%d/mem", pid);
fp = fopen(tmp, "r");
...
if (type == MEMTRACK_TYPE_GL) {
sprintf(tmp, "/proc/%d/smaps", pid);
smaps_fp = fopen(tmp, "r");
...
}
while (1) {
unsigned long uaddr;
unsigned long size;
char line_type[7];
int ret;
if (fgets(line, sizeof(line), fp) == NULL) {
break;
}
/* Format:
* gpuaddr useraddr size id flags type usage sglen
* 545ba000 545ba000 4096 1 ----p gpumem arraybuffer 1
*/
ret = sscanf(line, "%*x %lx %lu %*d %*s %6s %*s %*d\n",
&uaddr, &size, line_type);
if (ret != 3) {
continue;
}
if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) {
bool accounted = false;
/*
* We need to cross reference the user address against smaps,
* luckily both are sorted.
*/
while (smaps_addr <= uaddr) {
unsigned long start;
unsigned long end;
unsigned long smaps_size;
if (fgets(line, sizeof(line), smaps_fp) == NULL) {
break;
}
if (sscanf(line, "%8lx-%8lx", &start, &end) == 2) {
smaps_addr = start;
continue;
}
if (smaps_addr != uaddr) {
continue;
}
if (sscanf(line, "Rss: %lu kB", &smaps_size) == 1) {
if (smaps_size) {
accounted = true;
accounted_size += size;
break;
}
}
}
if (!accounted) {
unaccounted_size += size;
}
} else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
unaccounted_size += size;
}
}
...
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type, struct memtrack_record *records, size_t *num_records) { ... sprintf(tmp, "/d/kgsl/proc/%d/mem", pid); fp = fopen(tmp, "r"); ... if (type == MEMTRACK_TYPE_GL) { sprintf(tmp, "/proc/%d/smaps", pid); smaps_fp = fopen(tmp, "r"); ... } while (1) { unsigned long uaddr; unsigned long size; char line_type[7]; int ret; if (fgets(line, sizeof(line), fp) == NULL) { break; } /* Format: * gpuaddr useraddr size id flags type usage sglen * 545ba000 545ba000 4096 1 ----p gpumem arraybuffer 1 */ ret = sscanf(line, "%*x %lx %lu %*d %*s %6s %*s %*d\n", &uaddr, &size, line_type); if (ret != 3) { continue; } if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) { bool accounted = false; /* * We need to cross reference the user address against smaps, * luckily both are sorted. */ while (smaps_addr <= uaddr) { unsigned long start; unsigned long end; unsigned long smaps_size; if (fgets(line, sizeof(line), smaps_fp) == NULL) { break; } if (sscanf(line, "%8lx-%8lx", &start, &end) == 2) { smaps_addr = start; continue; } if (smaps_addr != uaddr) { continue; } if (sscanf(line, "Rss: %lu kB", &smaps_size) == 1) { if (smaps_size) { accounted = true; accounted_size += size; break; } } } if (!accounted) { unaccounted_size += size; } } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) { unaccounted_size += size; } } ... } |
C
gpuaddr useraddr size id flags type usage sglen
7565e000 00000000 4096 1 ----p gpumem arraybuffer 1
756bc000 00000000 65536 2 -r--p gpumem command 16
756cd000 00000000 65536 3 -r--p gpumem command 16
756de000 00000000 65536 4 -r--p gpumem command 16
756fb000 00000000 4096 5 ----p gpumem gl 1
75fe2000 00000000 262144 6 ----p gpumem gl 64
76023000 00000000 8192 7 ----p gpumem gl 2
76026000 00000000 8192 8 ----p gpumem gl 2
76029000 00000000 4096 9 ----p gpumem texture 1
...
94d71000 00000000 131072 362 ----p gpumem vertexarraybuff 32
94da0000 00000000 667648 176 --l-p gpumem texture 163
94e44000 00000000 131072 363 ----p gpumem any(0) 32
94e65000 00000000 131072 364 ----p gpumem any(0) 32
c0000000 00000000 17268736 31 --L-- ion egl_image 4216
c1100000 00000000 8257536 36 --L-- ion egl_surface 21
c1900000 00000000 8257536 164 --L-- ion egl_surface 21
c2100000 00000000 8257536 175 --L-- ion egl_surface 21
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | gpuaddr useraddr size id flags type usage sglen 7565e000 00000000 4096 1 ----p gpumem arraybuffer 1 756bc000 00000000 65536 2 -r--p gpumem command 16 756cd000 00000000 65536 3 -r--p gpumem command 16 756de000 00000000 65536 4 -r--p gpumem command 16 756fb000 00000000 4096 5 ----p gpumem gl 1 75fe2000 00000000 262144 6 ----p gpumem gl 64 76023000 00000000 8192 7 ----p gpumem gl 2 76026000 00000000 8192 8 ----p gpumem gl 2 76029000 00000000 4096 9 ----p gpumem texture 1 ... 94d71000 00000000 131072 362 ----p gpumem vertexarraybuff 32 94da0000 00000000 667648 176 --l-p gpumem texture 163 94e44000 00000000 131072 363 ----p gpumem any(0) 32 94e65000 00000000 131072 364 ----p gpumem any(0) 32 c0000000 00000000 17268736 31 --L-- ion egl_image 4216 c1100000 00000000 8257536 36 --L-- ion egl_surface 21 c1900000 00000000 8257536 164 --L-- ion egl_surface 21 c2100000 00000000 8257536 175 --L-- ion egl_surface 21 |
相关文章推荐
- ClipDrawable 截取图片片段实现缓缓加载图片
- Android开发笔记(十九)底部标签栏TabBar
- Android崩溃(一):小红点BadgeView导致的崩溃
- android - Animation and Graphics(OverView)
- Android图片加载缓存库<2>
- android 自定义view实现流式布局
- Android程序中读取使用已有的SQLite数据库
- Android Animations动画使用详解
- Android图片加载缓存库<1>
- Android 沉浸式状态栏攻略 让你的状态栏变色吧
- android 设置系统屏幕亮度
- Android 中 SQLite 性能优化
- Android 价格日历
- 关于Android Studio 的NDK环境
- Android 计算平台简介
- android的armeabi和armeabi-v7a
- android推送解决方案
- [Exception Android 19] - android.widget.HeaderViewListAdapter.isEnabled
- Android中string.xml,动态改变数据方法
- [Android]官网《Testing Support Library》中文翻译