前言html
本文翻译自Android开发者官网的一篇文档,主要用于从宏观上介绍内存管理须要注意的一些要点。android
中国版官网原文地址为:https://developer.android.google.cn/topic/performance/memory-overview。程序员
路径为:Android Developers > Docs > 指南 > Best practies > Performance > Overview of memory management缓存
正文安全
Android运行时ART和Dalvik虚拟机使用分页和内存映射(mmapping)管理内存。这意味着全部被修改过的内存——不管是经过分配新的对象仍是触摸被映射的页——仍然驻留在RAM中而且不能移除分页。惟一从应用中释放内存的方法是释放应用持有的对象引用,让内存可以被垃圾收集器使用。但有一个例外:若是系统想在其它地方使用内存,那么全部被映射但没有被修改的文件,好比代码,可能会被从RAM的分页中移除。app
本文将阐述Android如何管理应用进程和内存分配。更多关于如何更有效管理应用内存的信息,请查阅【管理应用的内存】。框架
垃圾收集ide
一个被管理的内存环境, 像ART或Dalvik虚拟机,保持追踪每一块内存分配。一旦虚拟机肯定某块内存再也不被程序使用,它会释放该内存回到堆中,而不须要程序员的任何干预。这个在被管理的内存环境中回收再也不被使用的内存的机制被称为垃圾收集。垃圾收集有两个目标:找到程序中在将来不会再被访问的数据对象;以及回收被那些对象使用的资源。性能
Android的内存堆是一个分代的内存堆,这意味着,基于被分配的对象的预期寿命和大小,它追踪着不一样的分配群组。例如,最近被分配的对象属于年轻代。当一个对象保持活跃了足够长的时间,它可能会被提高到老年代,后面还有一个永久代。动画
每个堆分代都有它本身的对象能够占据的特定的内存数量上限。任什么时候候某代开始填充时,系统会执行一个垃圾回收事件来尝试释放内存。这个垃圾收集的持续时长取决于它所收集的对象在哪一个代,以及在每一个代中有多少活跃对象。
虽然垃圾收集可能很是快,但它仍然会影响您应用的性能。一般您没法掌控代码中垃圾收集事件什么时候会发生。系统有一套正在运行的标准来决定什么时候执行垃圾收集。当知足标准时,系统会中止执行进程并开始垃圾收集。若是垃圾收集发生在一个密集的正在处理的循环(如动画或音乐回放期间)中间时,这可能会增长处理时间。这个增长可能潜在地推进应用中代码执行时间超过为有效和平滑帧渲染而建议的16ms阈值。
除此以外,您的代码流可能执行某些类型的工做:这类工做强迫垃圾收集事件更频繁地发生或者使它们延续得比日常时间更长。例如,若是在透明度混合动画的每一帧期间,您在一个for循环最里面部分分配多个对象,可能致使大量对象污染内存堆。在那种环境下,垃圾收集器会执行多个垃圾收集事件并会下降应用的性能。
更多关于垃圾收集的分代信息,请查阅【垃圾收集】。
共享内存
为了适合在RAM中所须要的一切,Android尝试跨进程分享RAM分页。Android能够经过以下方式实现这个目的:
由于共享内存的大量使用,肯定您的应用正在使用多少内存须要关注。关于正确肯定应用的内存使用,在【RAM使用研究】中进行探讨。
分配和回收应用内存
对于每一个应用进程,Dalvik堆被限制为单个虚拟内存范围。这定义了逻辑堆的大小,这个大小能够根据须要增加,但只能增加到系统为每一个应用定义的极限值。
堆的逻辑大小和堆使用的物理内存数量并不相同。当检查应用的堆时,Android会计算一个被称为Proportional Set Size(PSS),它会计算和其它进程共享的赃页和干净页——可是其数量只能与共享RAM的应用数成比例。PSS总数被系统当作是物理内存的足迹。更多关于PSS的信息,请查阅【RAM使用研究】指导。
Dalvik堆并不会压缩堆的逻辑大小,这意味着Android不会整理堆碎片来压缩空间。Android仅仅会在堆的结尾有未被使用的空间时压缩逻辑堆大小。可是,系统仍然会减小被堆使用的物理内存。垃圾收集发生之后,Dalvik会遍历堆而且找到未被使用的页,而后使用madvise把那些页返回到内核。因此,成对的分配和大块的从新分配可能致使回收全部(或者几乎全部)被使用的物理内存。但是,从小的分配中回收内存可能很是低效,由于用于小分配的页面可能仍然和尚未被释放的事物共享。
限制应用内存
为了维护功能的多任务环境,Android对每一个应用的对大小设置了一个硬性限制。依据整体上所拥有的可用RAM数量多少,确切的堆大小限制在设备之间是不一样的。若是您的应用已经到达了堆的容量而且尝试分配更多的内存,可能会收到OutOfMemoryError。
在某些状况下,您可能想查询系统来确切地知道您当前的设备有多少可用的堆空间——例如,为了肯定保留多少数据在缓存中是安全的。您能够经过调用getMemoryClass()查询系统来获取这个数据。这个方法会返回一个整数来指示应用堆可用的兆字节数。
切换应用
当用户在应用之间切换时,Android将不在前台的应用——也就是,对用户是不可见的或者运行一个前台service如音乐播放——保存在最近最少使用(LRU)缓存中。例如,当用户首先启动应用,就会为它建立一个进程;可是当用户离开这个应用,那个进程并不会退出。系统会缓存这个进程。若是用户稍后返回到该应用,系统会从新使用这个进程,从而让应用切换得更快。
若是应用拥有一个缓存的进程,而且保留当前不须要的内存,那么您的应用——即便当用户不是正在使用它——会影响系统的总体性能。当系统运行时内存不足,系统会从最近最少使用的进程开始杀死LRU缓存中的应用。系统也会考虑那些持有最多内存的进程,而且可能终止它们来释放RAM。
★ 注意:当系统开始杀死LRU缓存中的进程时,主要是从下往上进行的。系统也会考虑哪些进程消耗了更多的内存,而且这样的话,若是被杀死能够提供给系统更多的内存收获。在LRU列表中消耗的内存越少,您保留在列表而且可以快速恢复的机会就越大。
更多关于当不在前台运行时进程如何缓存以及Android如何决定哪些进程能够被杀死的信息,请查阅【进程和线程】指导。
结语
本文最大限度保持原文的意思,因为笔者水平有限,如有翻译不许确或不稳当的地方,请指正,谢谢!