Android 内存管理介绍

202 阅读8分钟

极力推荐文章:欢迎收藏 Android 干货分享

#####阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android

Android Runtime(ART)Dalvik虚拟机使用 分页 和 内存映射 来管理内存。 这意味着应用程序修改的任何内存(无论是通过分配新对象通过映射页面)都将保留在RAM中,并且不能被分页。 应用程序释放内存的唯一方法是释放应用程序持有的对象引用,即使垃圾收集器回收(GC)回收内存 。 比如:如果系统想要在其他地方使用该内存,则可以将任何未经修改的映射到mmap中文件(例如代码)分页出RAM

本页面介绍了Android如何管理应用程序进程和内存分配。 有关如何在应用程序中更高效地管理内存的更多信息,请参阅管理您的应用程序的内存。

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

1.Android 垃圾回收机制(GC) 2.共享内存 3.内存的申请与回收 4.内存限制 5.不同App切换时的内存管理

#1.Android 垃圾回收机制(GC)

ARTDalvik虚拟机的托管内存环境会跟踪每个内存分配情况。 一旦它确定一段内存不再被程序使用,它将它释放回堆(Heap)中,并且不需要程序员的任何干预。 回收托管内存环境中未使用内存的机制称为垃圾回收(GC)垃圾收集有两个目的: 1.在程序中查找将来不再使用的数据对象(Object) 2.回收这些对象所占用的内存资源。

Android 的内存是一个典型的堆内存(Heap),这意味着系统会根据被分配的对象的预期寿命和大小有不同的分配桶。 例如,最近分配的对象属于年轻一代。 当一个对象保持足够的活动时间时,它可以被提升到一个老一代,然后是一个永久的世代。

每个堆的生成都有自己占用内存的上限。任何时候一旦内存即将被填满,系统就会执行一个垃圾回收事件去试图释放内存。垃圾收集的持续时间取决于它正在回收的那个对象以及回收多少个正在活跃的对象。

尽管垃圾器回收的速度相当快,但它仍然可能会影响应用程序的性能。并且你一般不会控制垃圾器回收你代码事件的时间。 系统垃圾回收机制具有一定运行中的标准,这个标准主要用于确定何时执行垃圾收集。当条件满足时,系统停止执行进程并开始垃圾收集。

如果垃圾回收发生在密集的处理循环(如动画)或音乐播放期间,可能会增加处理时间。这种增长可能会推动您的应用程序执行代码超过推荐的16ms阈值,以实现高效流畅的帧渲染。

此外,您的代码流可能会执行各种强制垃圾收集事件的工作,或使其持续时间超过正常。例如,如果在alpha混合动画的每个帧期间在for循环的最内部分配了多个对象,则可能会占用大量的内存堆,并使用大量对象。在这种情况下,垃圾收集器将执行多个垃圾收集事件,并可能降低应用程序的性能。

有关垃圾收集的更多一般信息,请参阅垃圾收集。

#2.共享内存

为了适应不同的RAM需求,Android 尝试在不同进程之间共享内存,共享内存的方法如下:

    1. APP共享Framework框架代码以及资源

每个APP的进程都是从Zygote进程中分离出来的。 Zygote 进程: Zygote进程是在系统启动并加载Framwork框架代码和资源(如Activity Theme)时开始。 要启动一个新的应用程序进程,系统会从Zygote进程fork分离出来,然后在新进程中加载并运行应用程序的代码。 这种方法允许大部分分配给Framework框架代码和资源的RAM页面与所有应用程序进程之间共享。

    1. 大多数静态数据可以跨进程共享

大多数静态数据被映射到一个进程。这种技术允许数据在进程之间共享,并允许在需要时将其分页。 示例静态数据包括:Dalvik代码(通过将其放置在用于直接映射的预链接.odex文件中),应用程序资源(通过将资源表设计为可以被映射的结构以及通过对齐APK的zip条目) 以及.so文件中的本地代码等传统项目元素。

    1. Android使用显式分配的共享内存区域(使用ashmem或gralloc)共享同一个动态RAM。

例如,窗口表面使用应用程序和屏幕合成器之间的共享内存,游标缓冲区使用内容提供者和客户端之间的共享内存。

由于共享内存的广泛使用,确定您的应用使用多少内存需要谨慎。 在调查您的RAM使用情况中讨论了正确确定应用程序内存使用情况的技巧。如需获取更多内容,请看RAM使用情况分析详解。

#3.APP内存的申请与回收

Dalvik 虚拟机会限制每个应用程序进程的虚拟内存范围。它定义了逻辑堆的大小,并且可以根据需要增长,但只能达到系统为每个应用程序定义的限制。

堆的逻辑大小与堆使用的物理内存量不同。在检查应用程序的堆时,Android 会计算一个名为“比例集合大小** Proportion Set Size ”(PSS)** 的值,该值与其他进程共享的脏页面(Page)和干净页面(Page),并且数量与多少应用程序共享该RAM成正比。(PSS)总数是系统认为是您的物理内存的足迹。有关PSS的更多信息,请参阅RAM使用情况指南

Dalvik堆不压缩堆的逻辑大小,这意味着 Android不会整理堆以关闭空间。当堆的末尾有未使用的空间时,Android只能缩小逻辑堆的大小。然而,系统仍然可以减少堆使用的物理内存。在垃圾收集之后,Dalvik遍历堆并找到未使用的页面,然后使用madvise将这些页面返回给内核。 因此,成对的大块分配和释放应该会导致所有(或几乎全部)所使用的物理内存的回收。但是,从小分配中回收内存的效率可能会低得多,因为用于小分配的页面仍可能与尚未释放的其他内容共享。

#4.APP内存限制

为了维护一个主要的多功能环境,Android 对每个应用程序的堆大小设定了一个硬限制。 确切的堆大小限制根据设备有多少RAM可用而有所不同。 如果您的应用程序已达到堆容量并尝试分配更多内存,则可能会收到OutOfMemoryError

在某些情况下,您可能需要查询系统以确定在当前设备上有多少堆空间可用 。 例如,确定有多少数据可以安全地保留在缓存中。 你可以通过调用getMemoryClass()来查询这个数字。 此方法返回一个整数,指示可用于应用程序堆的兆字节数。

#5.不同App切换时的内存管理

当用户在应用程序之间进行切换时,Android会保留不在前台的应用程序(即对用户不可见,或者在最近最少使用(LRU)缓存中运行诸如音乐播放之类的前台服务)。 例如,当用户第一次启动应用程序时,会为其创建一个进程; 但是当用户离开应用程序时,该过程不会退出。 系统保持进程缓存。 如果用户稍后返回到应用程序,系统将重新使用该进程,从而使应用程序切换更快。

如果您的应用程序具有缓存的进程,并且保留了当前不需要的内存,那么您的应用程序(即使用户不使用它)也会影响系统的整体性能。 由于系统内存不足,它会以最近使用最少的进程开始,终止LRU缓存中的进程。 系统也考虑到保存最多内存的进程,并可以终止它们以释放RAM

注意:当系统开始在LRU缓存中查杀进程时,它主要是自下而上的。 系统也考虑哪些进程消耗更多的内存,从而为系统提供更多的内存增益。 在整个LRU列表中消耗的内存越少,留在列表中的机会就越好,并能够快速恢复。

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

微信关注公众号:  程序员Android,领福利