Context
情景:
- 在C++中用 malloc申请内存
- 用申请的内存读取 模型文件
- 释放内存,AndroidStudio的Profiler显示内存大小不变
分析工具
adb shell dumpsys meminfo com.albertsnow.graphicdemo
分析- Android Studio的profiler功能
输出形式
//仅用于数据名称演示,非本case的实际dump信息
Pss Private Private Swap Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 0 0 0 0 12288 9963 2324
Dalvik Heap 0 0 0 0 4952 2971 1981
TOTAL 0 0 0 0 17240 12934 4305
Native Heap: 0
TOTAL: 0 TOTAL SWAP (KB): 0
观察结果:
malloc内存分配在Private dirty部分,release后 Heap size已经下降,但是Private Dirty并没有下降。导致进程dump出的实际占用 内存不变
额外的实验现象:
- 手机亮灭屏后,dirty内存会被回收
- 该加载逻辑在Service中,Service在独立于应用包名进程的单独进程中。但将该逻辑移到主进程中,dirty也会被回收
推测:
是系统对不同的进程状态,有不同的回收策略
代码解决:
mmap(NULL, chunck_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
代替malloc。原理 StackOverFlow link
进程memory Private & Public
进程共享的内存(Android的SDK代码)为public。进程独享的为private
进程clean dirty
进程的虚拟内存以page(页,大小4K)为最小大小,加载于内存中。并且在disk的swap(交换)区备份,如果两方不一致(memory的更改,还没来得及写入swap)
举例:
- 进程A加载于内存中(分为2个page)
- 用户启动进程B,但内存只有2个page(也就是8K),但已经被A进程占用。
- 系统就会吧 进程A swap到磁盘上,空出的2个page给B进程用。
所以 memory与disk内存书写不一致,就是dirty memory。
而无法立即回收,更改Exel,在原来基础上写了很多。等到退出Exel(release)时,提醒文件已经被更改(memory is dirty)无法关闭(release)