0%

Android内存

memory-types.svg

  • RAM:最快的内存类型
  • zRAM:用于交换空间的RAM分区,数据进入zRAM会压缩,减小内存占用,从zRAM出来时会解压
  • Storage:持久化数据存储

https://developer.android.com/topic/performance/memory-management

内存页面

  • 缓存页:有Storage中的文件(代码或内存映射文件)
    • 私有页:一个进程拥有且不能共享
      • Clean:在Storage中未修改的文件副本,可由kswapd 删除增加可用内存
      • Dirty:在Storage中有文件副本,但是经过了修改,可有kswapd移动到zRAM中压缩以减小内存占用,增加可用内存
    • 共享页:多个进程使用
      • Clean:在Storage中有未修改的文件副本,可由kswapd删除增加可用内存
      • Dirty:在Storage中有文件副本,但是经过了修改,可由kswapd调用msync()活着munmap()写回Storage中,释放内存,增大可用内存 ()
  • 匿名页:Storage中没有对用的文件副本(代码运行时初始化的一些数据)
    • Dirty:可有kswapd移动到zRAM中压缩,减小内存占用,增大可用内存

Tip:Clean Page 因为在Storage中有持久化的缓存,所以内存回收时可以直接删除

内存不足管理

内存不足时会调用 onTrimMemory 通知应用内存不足

  • 内核交换守护进程 (kswapd),即上述内存页面中的kswapd对内存的管理
  • 低内存终止守护进程(LMK),使用oom_adj_score的分值来确定正在运行的进程优先级,来决定终止哪个进程。

评分由高到低进行kill

  • Background apps 后台应用
  • Previous app 上一个应用
  • Home app 主屏幕应用,启动器应用。??????
  • Services
  • Perceptible apps 可觉察的应用,例如:键盘,桌面组件等
  • Foreground app 前台应用
  • Persistent 持久性 属于系统
  • System 系统进程
  • Native 例如kswapd(内核交换守护进程)

计算内存占用量

  • RSS:非共享内存页面数量+共享内存页面数量
  • PSS:非共享页面数量+ 共享内存/process num的页面数量
  • USS:非共享的页面数量

从上看PSS在计算内存占用时,共享内存需要花费时间计算页面数量,而RSS不区分共享和非共享页面数量,所以更适合跟踪内存分配量变化。

JAVA 虚拟机内存问题

  • Runtime.getRuntime().maxMemory() 虚拟机可用的最大内存
  • Runtime.getRuntime().totalMemory() 虚拟机已申请使用的内存
  • Runtime.getRuntime().freeMemory() 虚拟机申请了未使用的内存
  • 可用内存 = maxMemory - (totalMemory-freeMemory)
    1
    2
    3
    4
    5
    6
    maxMemory:201326592=192MB
    totalMemory:9466560
    freeMemory:6067952
    usedMemory:9466560-6067952= 3398608 = 3318.953125 = 3.24MB
    availMemory = 201326592 - 3398608 = 188.7MB

    // largeheap=”true” 可以让虚拟机内存增大
pixel 4xl aosp android 10 小米10 Ultra
largeheap=”false” 192MB 256MB
largeheap=”true” 512MB 512MB

Android内存大小

ActivityManager.MemoryInfo

  • lowMemory 是否低内存
  • availMem 可用内存
  • totalMem总内存
  • threshold 阈值
    1
    2
    3
    4
    5
    6
    7
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    activityManager.getMemoryInfo(memoryInfo);
    boolean lowMemory = memoryInfo.lowMemory;
    long availMem = memoryInfo.availMem;
    long totalMem = memoryInfo.totalMem;
    long threshold = memoryInfo.threshold;

    当前进程内存

    1
    2
    3
    4
    5
    6
    7
    8
    9
    summary.code,21164  // apk,dex,jar,so,ttf,oat等
    summary.stack,80 // java栈 和 native栈
    summary.graphics,536 // 图形相关 私有Gfx, EGL和GL
    summary.java-heap,3192=3.24MB // java堆// 和上面usedMemory是一样的
    summary.native-heap,7584 // c++堆
    summary.system,6827 // 系统内存,包括共享内存
    summary.total-pss,46955 // 虚拟机,native,other,swap
    summary.private-other,7572 // 私有的clean+dirty - 虚拟机,native,code,stack,graphics
    summary.total-swap,5608 // 非pss swap
1
2
3
4
5
Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memoryInfo);
Map<String, String> memoryStats = memoryInfo.getMemoryStats();
String javaHeap = memoryStats.get("summary.java-heap");
String nativeHeap = memoryStats.get("summary.native-heap");