预备知识

页:

我们把磁盘分很多,我们把这个块称为页(Memory paging),同时也是硬盘和内存最小的交换单位(一般为4k).

如果你想了解更多请参阅wikipedia: Memory paging(英文)

内存映射文件(Memory-mapped file)

假设我有一个exe程序要运行,这个exe大小为5g,那么操作系统会将这个文件装载到内存(当然不会一次性装载完.).我们把这种操作称为内存映射文件(Memory-mapped file).

共享内存

操作系统很多资源是可用让多个程序共享的,比如动态库代码.在AndroidZygote在进行fork出一个app时,其内部包含很多共享的主题和资源等.在程序没有修改这些共享资源的时候,所有的程序的共享资源指向同一物理内存.


假设进程B修改动态库的内容,那么会将会拷贝动态库作为一个副本,然后在在副本里面修改.

Swap space

当内存不足时候linux操作会执行内存交换的操作,大白话将就是一些不重要的程序的内存换出到硬盘,腾出的内存空间给新任务使用,而这块空间在linux我们把它称为交换空间(Swap space).等不重要的程序被重新调度时在将硬盘数据重新载入,但是成本极高. Android虽然是linux,但是在内存不足的时候并不会执行内存交换操作,主要原因手机存储比较小,另外频繁的读取容易对多媒体存储硬件带来损失以及带来大量迁移操作会引起卡顿.

swap-space-linux-systems(英文)

VSS/RSS/PSS/USS

这四个是一个程序内存区域的一个术语

Vss = virtual set size

Rss = resident set size

Pss = proportional set size

Uss = unique set size

vss:虚拟空间大小,操作系统会让程序认为自己可以掌握整个内存,所以虚拟一个完整内存空间给程序,表示整个程序内存,实际和物理内存需要做一次地址转化.(这里是操作系统基础知识不在这里铺开)

Rss:程序实际占用的物理内存,包含共享内存的大小(比如加载动态就是一个共享内存),所以不方便查看实际自身所占用的内存

Uss:不包含共享内存的程序大小

Pss:两个内存区域大小的结合,第一个内存区域是自身非共享内存的大小(Uss),另一个共享内存所占的平均值,注意是平均值,这个平均值计算:假设共享内存为 4MB,然后这个共享内存被两个程序加载,那么 4MB/2=2MB.平均值是2MB.

Pss是我们最常拿来做内存分析指标.

举例:

假设有程序A程序B都被程序加载,操作分配一个虚拟存储空间给他们操作,大小为4G(这个就是Vss),

然后程序A程序B此时实际使用了内存了2G(Uss).

程序A程序B加载同一动态库xxx.so,而xxx.so大小为1G,那么程序A程序BRss就是3G

计算xxx.so平均值为 1G/2=0.5G.所以程序的Pss的为2.5G

举例2:
Android提供procrank方便我们查看我们的所有程序(默认以Pss倒序排序)

脏页和干净页

的概念前面已经讲解过,而内存映射文件(Memory-mapped file)也是单位进行映射的.假设某个代码在A页,然后修改A页里面的变量,那么这个页叫做脏页.对于共享内存也是同理.

Android 内存管控机制

详细权威的可以查看官网 进程间的内存分配

下图是一个典型的Android内存模式,RAM是内存,zRAM也是RAM,的一部分,而Storage可以理解为我们的硬盘.

可能zRAM大家并不了解,这里大致说下作用,当RAM不足时,会将部分在RAM内容压缩后放入zRAM,等内存充足时解压zRAM在放回RAM.

内存不足策略1:kswapd
kswapdlinux的一个守护进程用于在内存不足将干净页进行回收好腾出内存空间,而脏页则会进行zRAM压缩.这里非常好理解,如果是干净页那么需要时再从文件读取即可,而脏页因为修改过了和硬盘文件的不符合,无法从新读取.

内存不足策略2:LMK
kswapd的回收和压缩机制并不能解决所有问题,所以Android还有另一个守护进程低内存终止守护进程(LMK/Low Memory Killer))进行跟进一步的内存回收.LMK会根据一个叫OOM_ADJ_SCORE得到所有进程的优先级.(数值越低越不容易被杀死).

你可以通过:
cat proc/{pid}/oom_adj来查看自己进程的优先级

oom_adj的数值一般根据以下图排序(高到低,越下面越不容易被杀死):

图来自官方文档,下面的说明简单修改官网文档

以下是上表中各种类别的说明:

  • 后台应用:之前运行过且当前不处于活动状态的应用。LMK 将首先从具有最高 oom_adj_score 的应用开始终止后台应用。

  • 上一个应用:最近用过的后台应用。上一个应用比后台应用具有更高的优先级(得分更低),因为相比某个后台应用,用户更有可能切换到上一个应用。

  • 主屏幕应用:这是启动器应用。终止该应用会使壁纸消失。

  • 服务:服务由应用启动,可能包括同步或上传到云端。

  • 可觉察的应用:用户可通过某种方式察觉到的非前台应用,例如运行一个显示小界面的搜索进程或听音乐。可以简单理解用户可见APP,但是用户没有直接交互,比如有一个通知栏正在播放音乐

  • 前台应用:当前正在使用的应用。终止前台应用看起来就像是应用崩溃了,可能会向用户提示设备出了问题。

  • 持久性(服务):这些是设备的核心服务,例如电话和 WLAN。

  • 系统:系统进程。这些进程被终止后,手机可能看起来即将重新启动。

  • 原生:系统使用的极低级别的进程(例如,kswapd)。

在进行LMK时会多次调用onTrimMemory(level: Int)函数,参数level告诉当前内存紧张状态,你可以通过level的状态进行内存回收,否则你的app将被杀死.如果对于API 14的应用可以使用onLowMemory(),相当于onTrimMemory传入一个TRIM_MEMORY_COMPLETE(当前已经准备扫描完所有LRU列表进程,如果内存还不足将杀死你的进程).
另外这里有一个注意点,你不应该直接==判断level,应该使用>=或者<=进行操作,因为android未来没准插入新的状态.

  • 一个小Demo:
override fun onTrimMemory(level: Int) {super.onTrimMemory(level)//TRIM_MEMORY_UI_HIDDEN 用于告诉你,你应该回收ui视图,if (level>= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ) {rootView.removeAllViews()}}

常用技巧

getMemoryInfo()

MemoryInfo可以通过getMemoryInfo获取,通过MemoryInfo我们更加细腻度掌握内存状态.

Demo(来自google官方):

    public void doSomethingMemoryIntensive() {// Before doing something that requires a lot of memory,// check to see whether the device is in a low memory state.ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();if (!memoryInfo.lowMemory) {// Do memory intensive work ...}}// Get a MemoryInfo object for the device's current memory status.private ActivityManager.MemoryInfo getAvailableMemory() {ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();activityManager.getMemoryInfo(memoryInfo);return memoryInfo;}

生成HEAP DUMP

am命令

使用pid:am dumpheap {pid} /data/local/tmp/fileName.hprof
使用package:am dumpheap {package} /data/local/tmp/fileName.hprof

代码

android.os.Debug.dumpHprofData("/sdcard/dump.hprof");

以上生成的heap dump可以拖入as自带的profiler进行分析

但是如果想使用JAVA之类的工具分析(MAT,jprofiler)需要hprof-conv工具做下转化.
工具位于SDK目录:sdk/platform-tools/hprof-conv

  • 使用demo:
    hprof-conv in.hprof out.hprof

DDMS卡死等问题

ddms卡死jdk版本解决办法

参考

Android Memory Usage(英文)(注意pss描述不正确)
内存耗用:VSS/RSS/PSS/USS 的介绍
dumpsys文档
进程间的内存分配

Android内存相关相关推荐

  1. android 内核内存管理,Android内核相关内容总结

    要想充分掌握Android这一操作系统的应用,首先需要我们从Android内核的相关内容开始了解.在这里就为大家详细介绍一下相关的知识. Android操作系统是由谷歌推出的一款基于Linux平台开源 ...

  2. android释放acitity内存,Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  3. ANDROID内存优化(大汇总——中)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...

  4. Android内存泄漏就这样产生了

    为什么80%的码农都做不了架构师?>>>    1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及 ...

  5. Android内存优化(三)避免可控的内存泄漏

    相关文章 Android性能优化系列 Java虚拟机系列 前言 内存泄漏向来都是内存优化的重点,它如同幽灵一般存于我们的应用当中,有时它不会现身,但一旦现身就会让你头疼不已.因此,如何避免.发现和解决 ...

  6. Android 内存管理 amp;Memory Leak amp; OOM 分析

    1.Android 流程管理&内存 Android主要应用在嵌入式设备其中.而嵌入式设备因为一些众所周知的条件限制,通常都不会有非常高的配置,特别是内存是比較有限的. 假设我们编写的代 码其中 ...

  7. Android Pmem相关介绍

    http://fangjian0518.blog.163.com/blog/#m=0 Android Pmem相关介绍 2011-10-18 09:40:26|  分类: Android PMEM | ...

  8. Android内存管理

    Android是一个基于Linux实现的操作系统.但对于Linux内核来说,Android也仅仅只是一个运行在内核之上的应用程序,与其他运行在内核之上的应用程序没有任何区别.所以Android需要一套 ...

  9. 【Android 内存优化】自定义组件长图组件 ( 长图滚动区域解码 | 手势识别 GestureDetector | 滑动计算类 Scroller | 代码示例 )

    文章目录 一.GestureDetector 创建与设置 二.GestureDetector 触摸事件传递 三.触摸滑动操作 四.惯性滑动操作 五.长图滑动组件代码示例 六.运行效果 七.源码及资源下 ...

最新文章

  1. 逻辑模型三要素-数据结构
  2. Handler.removeMessages的作用,有时候为什么一定要先remove一下呢
  3. ansible-playbook剧本使用配置
  4. 3.1.9 二级页表
  5. kindeditor编辑器图片上传session丢失_微信公众号排版编辑器全指南!
  6. linux安装golang!!
  7. java的sas数据安全_使用sas中的do循环指定数据信息
  8. 电脑控制Android设备的软件——Total Control
  9. MongoDB最大连接数的查看与修改
  10. HP数组转JSON函数json_encode和JSON转数组json_decode函数的使用方法
  11. 基于UDP协议的Java聊天室
  12. inventor 波纹阵列_Inventor装配零部件阵列功能详解
  13. 转写给XJTU计算机系大一大二的童鞋
  14. PHP下制作图灵机器人程序
  15. 高级软件工程师必备的五大技能
  16. 小程序map组件一——使用腾讯地图个性化地图组件、腾讯云可视化大屏展示
  17. 数据结构堆栈 内存堆栈_零堆栈数据科学家第二部分秋天
  18. access数据库应用系统客观题_Access数据库选择题练习与答案
  19. mysql防火墙设置_mysql8 参考手册--MySQL企业防火墙配置参考
  20. post json数据

热门文章

  1. win10装系统时分区报错解决方法 无法找到新的分区也找不到现有分区
  2. STM32-UART串口应用
  3. [Unity] 战斗系统学习 9:构建 TPS 框架 4
  4. 鼎普计算机保密检查系统,敏感电子信息集中管控平台系统
  5. 做邮件服务系统的一点心得
  6. 【无标题】win11安装Oracle 12c [INS-32102] 指定的 Oracle 主目录用户已存在
  7. python 处理csv文件 一个简单的数据处理任务
  8. 线性代数第二章矩阵及其运算详解
  9. 速Geometric.Stackup.2.1.0.15228公差分析
  10. Java程序与以太坊智能合约交互