对32位手机崩溃的优化记录
# VMPeak 与 VMSize
在 Android 系统中,VMPeak 和 VMSize 是进程虚拟内存的相关指标,它们对于应用的内存管理和性能有直接影响。了解这些指标对于优化应用的内存使用、特别是在 32 位设备上的优化非常重要
- VMPeak 和 VMSize 的定义
- VMPeak: 进程所使用的虚拟内存的峰值值。这个值表示自进程启动以来,进程虚拟内存使用的最大值
- VMSize: 当前进程所使用的虚拟内存大小。它表示进程当前的虚拟内存使用量,包括代码、数据、堆和栈等
- 对进程的影响
- 内存使用管理:VMPeak 和 VMSize 是进程内存使用的两个重要指标。过高的 VMSize 可能会导致系统内存不足,尤其在设备 RAM 本身较少时,这可能导致系统频繁进行内存交换(swap)或杀死其他后台进程
- 性能影响: 高内存使用会影响应用和系统的整体性能。频繁的垃圾回收(GC)和内存管理开销会增加,导致应用响应变慢
- 崩溃风险: 如果 VMPeak 超过系统允许的最大虚拟内存(尤其在 32 位设备上,这个上限通常是 4GB),可能会导致内存分配失败,进而引起应用崩溃
虚拟地址空间的理论上限
在 32 位系统上,虚拟地址空间的理论上限是 4 GB(2^32 字节)。但是,由于操作系统和硬件保留了部分地址空间,实际应用程序可用的虚拟地址空间会少于 4 GB
详细分析
- 理论最大值: 32 位地址空间可以表示 4,294,967,296 字节(4 GB)
- 实际可用空间: 内核空间: 在许多 32 位操作系统中,内核和操作系统会占用一部分地址空间。例如,Linux 通常将最高的 1 GB 地址空间保留给内核,这意味着用户态程序可以使用的地址空间大约是 3 GB 系统保留和硬件映射: 系统和硬件还会保留部分地址空间用于硬件设备的内存映射和其他用途
# 查看 VmSize
# 获取 pid
adb shell ps | grep <process_name>
# 查看 VmSize
adb shell cat /proc/<pid>/status | grep VmSize
2
3
4
5
# 32 位设备上的优化建议
针对 32 位设备,内存限制更为严格,因为它们的虚拟地址空间有限(最大 4GB,但通常系统和其他应用占用一部分,因此实际可用远小于 4GB)。可以采取以下优化措施:
1.内存优化策略:
减少内存使用: 优化代码,减少不必要的对象创建和资源加载,特别是大对象和图像资源
使用高效数据结构: 选择合适的数据结构,避免使用过多的链表、哈希表等占用大量内存的数据结构
2.资源管理:
按需加载: 使用按需加载技术,只在需要时加载资源。避免在启动时加载所有资源
释放不需要的资源: 及时释放不再需要的资源,特别是大图片、音频和视频文件
优化图像: 使用压缩图像格式(如 WebP),并根据设备屏幕分辨率加载适当尺寸的图像
3.内存分析工具:
使用 Android Profiler: 通过 Android Studio 提供的内存分析工具,监控应用的内存使用,查找和修复内存泄漏
LeakCanary: 集成内存泄漏检测工具,如 LeakCanary,自动检测和报告内存泄漏
4.优化代码:
减少全局变量和单例: 避免过多使用全局变量和单例,它们会在整个应用生命周期中占用内存
优化算法: 确保算法的时间和空间复杂度最低,避免使用高复杂度的算法
5.垃圾回收优化:
减少临时对象创建: 尽量减少临时对象的创建,减少垃圾回收的频率
使用池化技术: 对于频繁使用的大对象,使用对象池(object pool)来重用对象,避免频繁的创建和销毁
通过以上措施,可以有效降低 VMPeak 和 VMSize,从而减少崩溃风险,提升应用在 32 位设备上的性能和稳定性
# base
# 获取 CPU ABIS
// 获取支持的cpu abi,返回一个数组。如 ['arm64-v8a', 'armeabi-v7a', 'armeabi']
Build.SUPPORTED_ABIS
// 设备的主要 CPU 架构,armeabi-v7a. 可以拿到运行时主CPU架构。 另外也可以通过 ApplicationInfo 对象拿
Build.CPU_ABI
// 设备的次要 CPU 架构
Build.CPU_ABI2
// 通过 ApplicationInfo 对象拿
PackageManager pm = getPackageManager();
String packageName = getPackageName();
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
String[] supportedABIs;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Field primaryCpuAbi = ApplicationInfo.class.getField("primaryCpuAbi");
primaryCpuAbi.setAccessible(true);
AsyncPLog.i("xxx", "primaryCpuAbi=%s", primaryCpuAbi.get(ai));
Field secondaryCpuAbi = ApplicationInfo.class.getField("secondaryCpuAbi");
secondaryCpuAbi.setAccessible(true);
AsyncPLog.i("xxx", "secondaryCpuAbi=%s", secondaryCpuAbi.get(ai));
}
} catch (Exception e) {
e.printStackTrace();
}
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
aapt dump badging your_apk_file.apk | grep "native-code": 查看 apk 是 32 位还是 64 位adb shell dumpsys package <package_name> | grep "cpuAbi": 通过 adb 查看架构, not workedadb shell getprop ro.product.cpu.abilist: 查看系统支持的 cpu 架构