概述
在内存优化前我们有必要借助一些工具来查看我们的 APP 目前使用内存的状况,为我们内存优化指明方向。
Android 中关于的工具很多,参考下表。所以我们要灵活地选用我们需要的工具。在定位内存问题的过程中,推荐使用涵盖一定初步定位和定位能力的工具,可以让我们一步到位地剖析问题、提升效率。
工具 | 分析问题 | 能力 | 备注 |
---|---|---|---|
top/procrank | 内存占用过大,内存泄漏 | 发现 | |
meminfo | |||
dmabug_dump | 分析ION内存 | ||
StrickMode | Activity 内存泄漏 | 自动发现+初步定位 | |
LeakCanary | Activity 内存泄漏 | 自动发现+定位 | |
Systrace | GC导致的卡顿 | 发现 | |
Memory Monitor/Memory Profiler | 申请内存大小和时间 | 发现 | Android Studio 3.0 采用全新的 Android Profiler 窗口取代 Android Monitor 工具。 |
HeapViewer | 查看APP内存分配大小和空闲内存大小 | 发现 | |
Allocation Tracker | 申请内存次数过多和多大,辅助定位GC log发现的问题 | 发现+定位 | |
Android Lint | 内存优化建议 | 发现+定位 | |
MAT | 内存泄漏 | 发现+定位 |
getprop
我们可以使用 adb shell getprop |grep vm
来看 Android 虚拟机对内存的一些配置:
1 | [dalvik.vm.heapgrowthlimit]: [256m] |
dalvik.vm.heapgrowthlimit 表示受控情况下每个进程可用的最大堆内存。dalvik.vm.heapsize 表示 设置了 android:largeHeap="true"
的应用可以使用的最大堆内存。
procrank
需要root权限才能运行
1 | bogon:TestSomething heqiang$ adb shell procrank |
输出结果是按照 PSS 值从大到小进行排列的。
- VSS:Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)是单个进程全部可访问的地址空间
- RSS:Resident Set Size 实际使用物理内存(包含共享库占用的内存)是单个进程实际占用的内存大小,对于单个共享库, 尽管无论多少个进程使用,实际该共享库只会被装入内存一次。
- PSS:Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
- USS:Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)USS 是一个非常非常有用的数字, 因为它揭示了运行一个特定进程的真实的内存增量大小。如果进程被终止, USS 就是实际被返还给系统的内存大小。
USS 是针对某个进程开始有可疑内存泄露的情况,进行检测的最佳数字。怀疑某个程序有内存泄露可以查看这个值是否一直有增加。
这些内存指标都是包含 Java 内存和 Native 内存的。
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
showmap
adb shell showmap
dumpsys meminfo
可以使用 adb shell dumpsys meminfo
来看系统内所有进程的内存使用情况:
1 | Applications Memory Usage (in Kilobytes): |
ION:
我们可以使用下面的命令来查看某个进程使用内存的情况:
1 | adb shell dumpsys meminfo -a <进程名称> |
输出结果:
1 | Applications Memory Usage (in Kilobytes): |
现在对上面输出内容的各项指标来做个解释:
横轴指标:
- Native Heap:Native 分配的内存,就是非 Java 代码分配的内存。不受Java Object Heap大小限制,但受限于系统内存。
- Dalvik Heap:Java对象分配的占据内存。
- Dalvik Other:类数据结构和索引占据内存
- Stack:栈内存
- Ashmem:匿名共享内存
- Other dev:内部driver占用的内存
- .so mmap:so库占用的内存
- .apk mmap:apk占用的内存
- .ttf mmap:ttf文件占用过的内存
- .dex mmap:
- .oat mmap:
- .art mmap:
- Other mmap
- App Summary:
- Java Heap:从 Java 或 Kotlin 代码分配的对象内存。
- Native Heap:从 C 或 C++ 代码分配的对象内存。不受Java Object Heap大小限制,但受限于系统内存。当然如果 RAM 快耗尽,memory killer 就会杀进程释放 RAM。
- Code:您的应用用于处理代码和资源(如 dex 字节码、已优化或已编译的 dex 码、.so 库和字体)的内存。
- Stack:您的应用中的原生堆栈和 Java 堆栈使用的内存。 这通常与您的应用运行多少线程有关。
- Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。 (请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)看代码中有没有直接调用opengl,如果没有可以忽略,那就主要是framework创建的。
- Private Other
- System
对于应用的内存,一般我们主要关注 App Summary 就行了。
进程空间中的 heap 空间是我们需要重点关注的,heap 空间完全由程序员控制,我们使用的 malloc、C++ new 和 java new 所申请的空间都是 heap 空间, 其中 C/C++ 申请的内存空间在 native heap 中,而 java 申请的内存空间则在 dalvik heap中。
Memory Profiler
Android 官方文档:使用 Memory Profiler 查看 Java 堆和内存分配
Mat
参考
《Android 移动性能实战》