e-works数字化企业网  »  文章频道  »  基础信息化  »  移动应用

Android 进程回收之LowMemoryKiller原理篇

2017/10/2    来源:云栖社区    作者:佚名      
关键字:Android  LowMemoryKiller  
在前面的文章Android进程保活一文中,对于LowMemoryKiller的概念做了简单的提及LowMemoryKiller简称低内存杀死机制。
    在前面的文章Android进程保活一文中,对于LowMemoryKiller的概念做了简单的提及。LowMemoryKiller简称低内存杀死机制。简单来说,LowMemoryKiller(低内存杀手)是Andorid基于oomKiller原理所扩展的一个多层次oomKiller,OOMkiller(Out Of Memory Killer)是在Linux系统无法分配新内存的时候,选择性杀掉进程,到oom的时候,系统可能已经不太稳定,而LowMemoryKiller是一种根据内存阈值级别触发的内存回收的机制,在系统可用内存较低时,就会选择性杀死进程的策略,相对OOMKiller,更加灵活。
 
    在讲解LowMemoryKiller之前,先看另一个概念:OOMKiller。
 
    Linux下有一种OOM KILLER 的机制,它会在系统内存耗尽的情况下,启用自己算法有选择性的kill 掉一些进程。
 
    OOMKiller
 
    当我们启动应用时,需要向系统申请内存,即进行malloc的操作,进行malloc操作如果返回一个非NULL的操作表示申请到了可用的内部你。事实上,这个地方是可能存在bug的。Linux有一种内存优化机制,即:允许程序申请比系统可用内存更多的内存(术语:overcommit),但是Linux并不保证这些内存马上可用,如果凑巧你申请到的内存中在你需要使用的时候还没有完全释放出来,这个时候就会触发OOM killer了。内核代码为:mm/oom_kill.c,其调用顺序为:
 
    malloc -> _alloc_pages -> out_of_memory() -> select_bad_process() -> badness()
 
    然而,系统的物理内存往往是有限的,这就需要在使用过程中杀掉一些无用的进程以腾出新的内存。在Android系统中,AmS需要和Linux操作系统有个约定,即将要谈到的Linux内核的内存管理控制系统是如何通知AMS内存不足的。
 
    Java虚拟机运行时都有各自独立的内存空间,应用程序A发生Out Of Memory并不意味着应用程序B也会发生Out Of Memory,很有可能仅仅是A程序用光了自己内存的上限,而系统内存却还是有的。所以说,单纯的AmS是无法获知系统内存是否低的。
 
    那么,Android系统是如何知道"系统内存低"或者"系统内存不够用"呢?从Android底层的Linux来讲,由于其并未采用磁盘虚拟内存机制,所以应用程序能够使用的内存大小完全取决于实际物理内存的大小,所以,"内存低"的含义就是实际物理内存已经被用得所剩无几了。看下面一幅图:
 
    Android 进程回收之LowMemoryKiller原理篇
 
    在Android中运行了一个OOM 进程,即Out Of Memory。该进程启动时会首先向Linux内核中把自己注册为一个OOM Killer,即当Linux内核的内存管理模块检测到系统内存低的时候就会通知已经注册的OOM进程,然后这些OOM Killer就可以根据各种规则进行内存释放了,当然也可以什么都不做。
 
    Android中的OOM Killer进程是仅仅适用于Android应用程序的,该进程在运行时,AmS需要把每一个应用程序的oom_adj值告知给Killer。这个值的范围在-16到15,值越低,说明越重要,这个值类似于Linux系统中的进程nice值,只是在标准的Linux中,有其自己的一套Killer机制。
 
    重要:**当发生低内存的条件时,Linux内核管理模块通知OOM Killer,Killer则根据AmS所告知的优先级,强制退出优先级低的应用进程。**
 
    LowMemoryKiller
 
    前面,我们谈到了OOMKiller的一些知识,在理解OOMKiller的时候注意两点:
 
    1.LowMemoryKiller是被动杀死进程;
 
    2.Android应用通过AMS,利用proc文件系统更新进程信息。
 
    进程优先级及oomAdj
 
    关于这方面的知识,前文有过介绍Android进程保活。这里在简单的介绍下。
 
    Android会尽可能长时间地保持应用存活,但为了新建或运行更重要的进程,可能需要移除旧进程来回收内存,在选择要Kill的进程的时候,系统会根据进程的运行状态作出评估,权衡进程的“重要性“,其权衡的依据主要是四大组件。如果需要缩减内存,系统会首先消除重要性最低的进程,然后是重要性略逊的进程,依此类推,以回收系统资源。在Android中,应用进程划分5级:
 
  • 前台进程(Foreground process)

  • 可见进程(Visible process)

  • 服务进程(Service process)

  • 后台进程(Background process)

  • 空进程(Empty process)

  • 前台进程(Foreground process)
 
    用户当前操作所必需的进程。如果一个进程满足以下任一条件,即视为前台进程:
 
  • 包含正在交互的Activity(如resumed)

  • 包含绑定到正在交互的Activity的Service

  • 包含正在“前台”运行的Service(服务已调用startForeground())

  • 包含正执行一个生命周期回调的Service(onCreate()、onStart() 或 onDestroy())

  • 包含一个正执行其onReceive()方法的BroadcastReceiver
 
    可见进程(Visible process)
 
    没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:
 
    包含不在前台、但仍对用户可见的 Activity(已调用其 onPause() 方法)。例如,如果前台 Activity 启动了一个对话框,允许在其后显示上一Activity,则有可能会发生这种情况。
 
    包含绑定到可见(或前台)Activity 的 Service。
 
    服务进程(Service process)
 
    正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
 
    后台进程(Background process)
 
    包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity会恢复其所有可见状态。
 
    空进程(Empty process)
 
    不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间,这就是所谓热启动 。为了使系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
 
    根据进程中当前活动组件的重要程度,Android会对进程的优先级进行评定。下表是进程优先级的表(主要针对4.03-5.x)。
 
Android 进程回收之LowMemoryKiller原理篇
 

责任编辑:李欢
本文为授权转载文章,任何人未经原授权方同意,不得复制、转载、摘编等任何方式进行使用,e-works不承担由此而产生的任何法律责任! 如有异议请及时告之,以便进行及时处理。联系方式:editor@e-works.net.cn tel:027-87592219/20/21。
e-works
官方微信
掌上
信息化
编辑推荐
新闻推荐
博客推荐
视频推荐