Android内存管理概述

   **本文为翻译官方文档,如有错误,请指正**

Android内存管理概述

Android运行时(ART)和Dalvik虚拟机使用分页和内存映射来管理内存。这意味着一个应用程序修改的任何内存,无论是通过分配新的对象或者触摸内存映射页面--都将驻留在RAM中,不能被分页。释放一个应用内存的唯一方式是释放被程序持有的对象引用,在垃圾回收之后内存变为可用。假如系统想在任何地方使用该内存,则任何未修改的文件内存映射都可以被移除RAM。

这篇文章说明Android如何管理进程和内存分配。更多在应用程序中如何更加高效管理内存,请看管理应用内存

垃圾回收

一个托管内存环境,像ART或者Dalvik虚拟机,保持对每一次内存分配的跟踪。一旦确定一块内存不在被程序使用,将它释放回堆,而不需要程序员的额外操作。在托管内存环境恢复未使用的内存机制就叫垃圾回收。垃圾回收有2个目的:找到将来不会被访问的数据对象,并回收这些对象的资源。

Android堆内存是一代(gennerational one)的,意味着他们是不同的桶分配(buckets of allocations),跟踪依赖于正在分配的对象生命周期和大小。例如,最近分配的对象属于存在于年轻代,存活时间久的对象就晋升为老年代,紧随其后是永久的一代。

每一个堆栈代都有其独立的占用对象内存上限。任何时候,只要一个代占用满了,系统执行垃圾回收为了空出内存。垃圾回收持续时间完全依赖于某一代回收的对象和每一代中还有多少对象存活着。

虽然垃圾回收非常快,它依旧可能影响程序性能。通过代码,你不能完全控制垃圾回收何时执发生。系统具有运行的一套标准,用于确定何时执行垃圾收集。当条件被满足,系统挂起进程并执行垃圾回收。如果垃圾回收发生在一个密集处理之间,像执行动画或者播放音乐中间,它会增加进程执行时间。这种增加可能会潜在的推动代码执行超过建议的16ms阈值,以实现高效和平滑的帧渲染。

此外,你的代码可能执行各种各样的工作,导致经常强制执行垃圾回收事件或者使得垃圾回收事件比正常持续更长时间。例如,在alpha混合动画的每一个帧期间,在for循环的最内部分配过多的对象,则可能导致过多的对象污染你的内存堆。在这种情况下,垃圾回收器执行多次垃圾回收事件可能导致程序性能降低。

更多关于垃圾回收的信息,参考垃圾回收

共享内存

为了适用RAM中需要的一切,Android尝试跨进程共享RAM分页。它可以在以下方式中使用。

  • 每一个从现有Zygote进程fork出来的进程。当系统启动并加载公共框架代码和资源(例如activity主题)是启动Zygote进程。为了启动一个新的应用进程,系统fork Zygote进程去加载和运行应用代码在这个新的进程中。这种方法允许大部分分配给公共框架和资源的RAM分页被夸所有的应用进程共享。
  • 大多数静态数据被划分到一个进程中。这种技术允许数据在进程间共享,当需要的时候也允许数据被移出分页。比如静态数据包括:Dalvik代码(通过将其放置在预先连接的.odex文件进行直接的内存映射),应用资源(通过将资源表格设计为可以内存映射的数据结构,并通过对其APK的zip条目),和传统的项目元素例如在.so文件中的本地代码。
  • 在很多方面,Android通过使用明确分配的共享内存区域实现进程间共享同样的动态RAM(例如通过匿名共享内存Anonymous shared memory或者gralloc)。例如,窗口页面使用应用程序和屏幕合成器间的共享内存,光标缓存区使用内容提供者和客户端间的共享内存。

由于大量使用内存共享,需要注意决定您的应用程序使用多少内存。正确决定应用程序使用内存的技术在调查RAM使用中被讨论。

分配和恢复应用内存

Dalvik堆为每个应用进程限制单一的虚拟内存范围。这定义了应用逻辑堆大小,它可以随着需要扩展但只能达到系统为每个应用程序限定的大小。

堆的逻辑大小与堆使用的物理内存量不相同。当检查应用程序堆时,Android访问实际使用的内存计算一个值,该值称为与其它进程共享脏分页和干净分页的比例,但只能和共享RAM的应用程序成正比。实际使用内存总量是系统考虑你的物理内存占用。更多关于PSS(Proportional Set Size)的信息,请看调查RAM使用情况导读。

Dalvik堆不会对堆的逻辑大小进行压缩,这意味着Android不会整理堆内存碎片以关闭空间。Android仅仅能压缩处于堆末尾未使用空间中的逻辑堆大小。然而,系统仍旧能回收被堆使用的物理内存。在垃圾回收之后,Dalvik操作堆并找到未使用的分页,并通过使用madvise把这些分页返回给内核。因此,配合分配和重新分配大块地址,可能导致回收全部(几乎所有)已使用的物理内存。然而,从小的分配内存中回收内存可能效率要低很多,因为被小的内存分配占用的分页,可能同时也被其它未释放的其它内容共享。

限制应用程序内存

为了维持多任务的工作环境,Android为每一个应用程序设置了硬性的堆上线。准确的上线,依赖于设备全部能提供的RAM大小在不同设备之间有不同。假如你的应用程序已经快到堆容量了并且依旧尝试分配更多内存,就会返回一个内存溢出错误。

在很多情况下,你希望查系统,以确定在当前设备上你可以的堆大小。例如,确定在缓存文件中保存多少数据是安全的。你可以通过调用getMemoryClass()来查询系统的这个数字。这个方法返回一个数字表明你的应用程序有多少兆可用字节

切换应用程序

当用户切换应用程序,在用户最近使用(LRU)的缓存中,Android保持那些不在前台的应用程序--那些对于用户不可见或者像音乐播放器在前台运行的服务。例如,当用户第一次启动一个应用的时候,系统为它创建了一个进程,但是当用户离开这个应用的时候,这个进程并没有被退出。系统保持这个进程在缓存中。假如用户之后回到这个应用程序,系统恢复这个进程,从而 可以使得切换应用程序更快。

假如你的应用程序拥有缓存进程并且保留了那些没有使用的内存-即使用户没有使用应用程序--它也会影响系统的整体性能。当系统在低内存运行的时候,系统开始杀死那些最近很少使用的在LRU缓存进程。系统还考虑那些持有大部分内存的进程并考虑终止他们以释放RAM。

注意:当系统开始杀死LRU缓存中的进程时,首先从低向上开始工作。系统也考虑那些占用很多内存并且杀死它系统可以获取更多内存的进程。在LRU列表中占用的内存越少,在列表中保留下来的机会就越大,并且可以更加快的恢复。

更多关于进程没有在前台运行如果保存在缓存中,并且Android设备如何选择哪一个进程去杀死,请看进程和线程导读。

 

原文地址:https://developer.android.google.cn/topic/performance/memory-overview.html

posted @ 2017-06-07 16:58  流浪三毛  阅读(385)  评论(0)    收藏  举报