1. 背景
公司有一個測試項,執(zhí)行adb shell dumpsys meminfo + pkg
命令查看內存信息:
malk@malk:am$ adb shell dumpsys meminfo com.meizu.safe
Applications Memory Usage (in Kilobytes):
Uptime: 103881237 Realtime: 263009590
** MEMINFO in pid 32506 [com.meizu.safe] **
Pss Private Private SwapPss Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 18894 18832 0 0 32768 20940 11827
Dalvik Heap 6713 6624 0 0 10615 6519 4096
Dalvik Other 1485 1484 0 0
Stack 700 700 0 0
Ashmem 2 0 0 0
Other dev 4 0 4 0
.so mmap 2717 136 40 39
.apk mmap 44952 0 35456 0
.ttf mmap 45 0 0 0
.dex mmap 5344 8 1324 0
.oat mmap 2728 0 0 0
.art mmap 2871 2368 4 2
Other mmap 1090 4 64 0
EGL mtrack 12168 12168 0 0
Unknown 1535 1532 0 0
TOTAL 101289 43856 36892 41 43383 27459 15923
App Summary
Pss(KB)
------
Java Heap: 8996
Native Heap: 18832
Code: 36964
Stack: 700
Graphics: 12168
Private Other: 3088
System: 20541
TOTAL: 101289 TOTAL SWAP PSS: 41
一直有個疑問,dump信息中EGL mtrack/GL mtrack兩項分別代表什么意思诚隙?
google官方解釋:
EGL memtrack
You will see this column when display driver’s memtrack module is enabled
Before Lollipop5.1, this column is named “Graphics”.
EGL memtrack memory is the summary of all surface buffers(the surface buffer increases to triple buffer after Android 4.1) and the size of the Atlas buffer.
However, Atlas buffer is actually a shared memory and shouldn’t be accounted into each UI process’ memory usage to overcount the memory usage.
Both surface buffer and Atlas buffer’s memory quota is reserved in project’s memory estimation, thus the memory usage of these buffers should be separately
accounted from process’ memory usage. So when you measure process’ memory usage, you can ignore this column.
GL memtrack
You will see this column when display driver’s memtrack module is enabled
Before Lollipop5.1, this column is named “GL”.
HW acceleration memory is partially counted in process PSS. For example, for QCT platform the HW acceleration memory is partially counted in the PSS of /dev/kgsl-3d0
as we mentioned in the “Gfx dev” section. GL memtrack memory usage calculates the unaccounted /dev/kgsl-3d0 memory regions which PSS value equals 0.
Please be noticed that the summation of GL memtrack and Gfx dev doesn’t reflect the complete HW acceleration memory since the full HW acceleration memory usage
should be counted with the VSS of /dev/kgsl-3d0. So the “TOTAL” value of dumpsys meminfo is smaller than actual physical memory usage.
只看簡介有些難以理解召噩,我想了解它的生成原理纸兔,找了半天省有,發(fā)現(xiàn)qualcomm和mtk平臺相關代碼沒有開源,還好samsung開源了代碼。
先說明一下這兩項的含義:
name | description |
---|---|
EGL mtrack | gralloc分配的內存胞得,主要是窗口系統(tǒng),SurfaceView/TextureView和其他的由gralloc分配的GraphicBuffer總和 |
GL mtrack | 驅動上報的GL內存使用情況屹电。 主要是GL texture大小阶剑,GL command buffer,固定的全局驅動程序RAM開銷等的總和 |
2. Memory Tracker
2.1 Memory Tracker是什么
Memory Tracker也稱memtrack危号,是一個hal層的庫牧愁,不同平臺庫的名稱不同,實現(xiàn)方式也有差異外莲。
以samsung平臺為例:
Name: memtrack.exynos5.so
File Directory:/system/lib64/hw/
Source code : hardware/samsung_slsi/exynos/libmemtrack/
Memory Tracker 主要目標是能夠跟蹤以任何其他方式無法跟蹤的內存猪半,例如由進程分配但未映射到進程地址空間的紋理內存。
第二個目標是能夠將進程使用的內存分類為GL偷线,graphics等磨确。所有的內存大小應該在實際的內存使用情況下,考慮到stride声邦,bit depth乏奥,page size等。
EGL mtrack/GL mtrack這兩項的數(shù)據(jù)就是通過memtrack獲取的亥曹。
2.2 adb shell dumpsys meminfo實現(xiàn)原理
先看一下adb shell dumpsys meminfo +pkg
的流程
1. Ams在systemserver啟動時邓了,創(chuàng)建了meminfo服務,所以才能dumpsys meminfo:
ServiceManager.addService("meminfo", new MemBinder(this));
2.執(zhí)行dumpsys操作后媳瞪,會去獲取兩部分信息:
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
bool foundSwapPss;
stats_t stats[_NUM_HEAP];
memset(&stats, 0, sizeof(stats));
load_maps(pid, stats, &foundSwapPss);//獲取/proc/$pid/smap節(jié)點信息
struct graphics_memory_pss graphics_mem;
if (read_memtrack_memory(pid, &graphics_mem) == 0) {//獲取graphics drivers上報的內存信息
stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
stats[HEAP_GL].pss = graphics_mem.gl;
stats[HEAP_GL].privateDirty = graphics_mem.gl;
stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
}
}
static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
{
char tmp[128];
FILE *fp;
sprintf(tmp, "/proc/%d/smaps", pid);
fp = fopen(tmp, "r");
if (fp == 0) return;
read_mapinfo(fp, stats, foundSwapPss);
fclose(fp);
}
/*
* Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
* 獲取不計算在/proc/pid/smaps里的graphics memory信息
*/
static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
{
if (!memtrackLoaded) {
return -1;
}
struct memtrack_proc* p = memtrack_proc_new();
if (p == NULL) {
ALOGW("failed to create memtrack_proc");
return -1;
}
int err = read_memtrack_memory(p, pid, graphics_mem);
memtrack_proc_destroy(p);
return err;
}
3. graphics memory數(shù)據(jù)類型
graphics memory分為五種類型數(shù)據(jù):
- MEMTRACK_TYPE_OTHER = 0
- MEMTRACK_TYPE_GL = 1
- MEMTRACK_TYPE_GRAPHICS = 2
- MEMTRACK_TYPE_MULTIMEDIA = 3
- MEMTRACK_TYPE_CAMERA = 4
我看到libmemtrack中有判斷骗炉,只接收兩種數(shù)據(jù),其他數(shù)據(jù)對應的代碼沒有找到:
memtrack_exynos.c
if (type == MEMTRACK_TYPE_GL) {
return mali_memtrack_get_memory(pid, type, records, num_records);
} else if (type == MEMTRACK_TYPE_GRAPHICS) {
return ion_memtrack_get_memory(pid, type, records, num_records);
}
MEMTRACK_TYPE_GL = GL mtrack材失,MEMTRACK_TYPE_GRAPHICS = EGL mstrack
2.3 Memory Tracker實現(xiàn)原理
graphics memory的數(shù)據(jù)是由graphics driver統(tǒng)計的痕鳍,統(tǒng)計方式會因平臺不同而有所差異硫豆,即使相同應用龙巨,不同平臺讀取的數(shù)據(jù)也可能不相同笼呆。
Memory Tracker做的事情就是將graphics driver統(tǒng)計好的數(shù)據(jù)從節(jié)點讀取并格式化。
以samsung平臺為例旨别,memtrack.exynos5.so庫做的事情很簡單诗赌,根據(jù)上層傳遞的type讀取對應節(jié)點,獲取內存信息秸弛。
memtrack_exynos.c
if (type == MEMTRACK_TYPE_GL) {
return mali_memtrack_get_memory(pid, type, records, num_records);
} else if (type == MEMTRACK_TYPE_GRAPHICS) {
return ion_memtrack_get_memory(pid, type, records, num_records);
}
2.3.1 MEMTRACK_TYPE_GL
如果上層傳遞的type類型為MEMTRACK_TYPE_GL铭若,對應GL mtrack,說明需要獲取的是驅動程序報告的GL內存使用递览。它主要是GL紋理大小叼屠,GL命令緩沖區(qū),固定的全局驅動程序RAM開銷等的總和绞铃。這些數(shù)據(jù)儲存在/d/mali/mem/
目錄下的節(jié)點中(samsung)镜雨,由mali庫(或者其他平臺的渲染庫)進行統(tǒng)計。
以samsung平臺儿捧,com.meizu.safe應用為例荚坞,我們查看其數(shù)據(jù):
1|m17:/ # ps | grep safe
system 32459 1174 1849812 127628 SyS_epoll_ 7b483472a0 S com.meizu.safe:MzSecService
system 32506 1174 2904076 225528 SyS_epoll_ 7b483472a0 S com.meizu.safe
m17:/ #
m17:/ #
m17:/ # cat /d/mali/mem/32506_76/mem_profile
com.meizu.safe:
Channel: Unnamed (Total memory: 2384536)
7: 226 / 14464
8: 297 / 47520
9: 16 / 6272
13: 166 / 684696
14: 68 / 601960
15: 4 / 79352
16: 3 / 98304
17: 5 / 327680
18: 4 / 524288
Channel: Default Heap (Total memory: 1678048)
13: 14 / 60744
14: 2 / 27352
16: 6 / 196672
18: 4 / 749088
20: 1 / 644192
Channel: Framepool (Total memory: 0)
(empty)
Channel: Frame Internal (Total memory: 32768)
16: 1 / 32768
Channel: GPU Program (Total memory: 40960)
16: 1 / 40960
Channel: EGL Color Plane (Total memory: 4096)
13: 1 / 4096
Channel: GLES VAO (Total memory: 0)
(empty)
Channel: Image Descriptor (Total memory: 352)
5: 16 / 256
7: 1 / 96
Channel: Texture (Total memory: 6252064)
6: 1 / 32
10: 1 / 512
11: 1 / 1024
12: 1 / 2048
14: 2 / 18816
16: 1 / 51008
17: 7 / 716608
19: 1 / 266240
21: 1 / 1048576
22: 1 / 4147200
Channel: Buffer (Total memory: 1204288)
7: 1 / 64
15: 1 / 24576
18: 1 / 131072
21: 1 / 1048576
Channel: CRC Buffer (Total memory: 102400)
13: 1 / 4096
16: 3 / 98304
Total allocated memory: 11699512
分類說明:
name | description |
---|---|
Default Heap | gpu內部結構的內存分配。是gpu中最基礎的內存分配 |
Framepool | framepool是gpu內部的概念菲盾,這個channel統(tǒng)計為framepool結構分配的內存颓影。很多函數(shù),例如eglSwapBuffers可能會引起這個channel的內存增加 |
Frame Internal | tiler是gpu內部的概念懒鉴,這個channel統(tǒng)計為tiler結構分配的內存诡挂。很多函數(shù),例如glCreateXXXSurface可能會引起這個channel的內存增加 |
GPU Program | glLinkProgram被調用時临谱,需要分配相應內存來存放shader code咆畏,那么這段內存將被記錄進GPU Program |
Image Descriptor | image instance是gpu內部的概念,這個channel統(tǒng)計為image instance結構分配的內存吴裤。很多函數(shù)旧找,例如glDrawXXX可能會引起這個channel的內存增加 |
EGL Color Plane | 為color planes分配的內部buffer。一些函數(shù)麦牺,例如gpu的回調函數(shù)可能會引起這個channel的內存增加 |
GLES VAO | VAO是一個保存了所有頂點數(shù)據(jù)屬性的狀態(tài)結合钮蛛,它存儲了頂點數(shù)據(jù)的格式以及頂點數(shù)據(jù)所需的VBO對象的引用。 |
Texture | 紋理 |
Buffer | glBufferData被調用時剖膳,需要分配內存來存放要導入的data魏颓,這段內存將被記錄進Buffer |
CRC Buffer | 一個color buffer的CRC buffer。一些函數(shù)吱晒,例如gpu的回調函數(shù)可能會引起這個channel的內存增加 |
2.3.1 MEMTRACK_TYPE_GRAPHICS
MEMTRACK_TYPE_GRAPHICS對應EGL mtrack甸饱,獲取的是gralloc內存使用情況。這些數(shù)據(jù)儲存在/sys/kernel/debug/ion/clients/
目錄的節(jié)點下(samsung)。
首先說明叹话,graphic memory由進程觸發(fā)分配偷遗,但是不會映射到進程的地址空間。
但是計算時驼壶,這部分內存可能會計算到應用的內存中氏豌。
以samsung平臺為例:
對于沒有TextureView和SurfaceView的應用,這個數(shù)值的大小應該是系統(tǒng)默認配置的Buffer數(shù)量*單個buffer的內存大小
.目前系統(tǒng)默認BufferQueue中Buffer數(shù)量是3热凹,那么EGL mtrack = 3 * 單個buffer的內存大小
泵喘。
還是以com.meizu.safe應用為例,當應用在前臺時般妙,我們查看其數(shù)據(jù):
m17:/ # cat /sys/kernel/debug/ion/clients/32506-0
buffer task pid thread tid size # procs flag
------------------------------------------------------------------------------------------
ffffffc00e70d880 surfaceflinger 1069 Binder:1069_4 1241 4153344 1 40
ffffffc02e16b800 surfaceflinger 1069 Binder:1069_4 1241 4153344 1 40
ffffffc06baa3100 surfaceflinger 1069 Binder:1069_2 1075 4153344 1 40
------------------------------------------------------------------------------------------
heap_name: size_in_bytes size_in_bytes(pss)
ion_noncontig_he: 12460032 12460032
其中ion_noncontig_he
代表這個應用由gralloc分配的內存總和纪铺。
這里有一個要注意的點,按home鍵讓應用退到后臺時碟渺,ion_noncontig_he的值就為0霹陡。這是一個優(yōu)化。
看完單個應用止状,我們再看一下機器整體的數(shù)據(jù):
清空多任務烹棉,解鎖進入桌面:
(1)adb shell dumpsys meminfo
查看總共的EGL mtrack數(shù)值。
total = 18380K
(2)adb shell dumpsys meminfo surfaceflinger
查看SurfaceFlinger的值
cat對應節(jié)點:
SurfaceFlinger沒有EGL mtrack這項統(tǒng)計
雖然app對應的BufferQueue的GraphicBuffer都是由SurfaceFlinger通過gralloc申請的怯疤,但是在samsung平臺上浆洗,EGL mtrack這部分數(shù)據(jù)并不算在SurfaceFlinger進程。
(3)分別查看system_server集峦、launcher伏社、systemui、recent的數(shù)據(jù)
| PkgName | EGL mtrack |
| ------------- |:-------------:| -----:|
| system_server | 4224 |
| com.android.systemui | 1988 |
| com.meizu.flyme.launcher | 12168 |
| com.android.systemui:recents | 0 |
| total | 18380 |
各個應用EGL mtrack數(shù)據(jù)加起來正好等于總和塔淤。