美文网首页
android内存管理

android内存管理

作者: 小面包屑 | 来源:发表于2017-10-30 16:51 被阅读0次

    内存管理机制概述

    Android 的内存管理机制可以简单概括为:系统没有为内存提供交换区,它使用 paging (页式调度)与 memory-mapping(mmapping) 来管理内存。

    为什么没有提供交换区?

    在linux里面,当物理内存不够用了,而又有新的程序请求分配内存,那么linux就会选择将其他程序暂时不用的数据交换到物理磁盘上(swap out),等程序要用的时候再读进来(swap in)。这样做的坏处显而易见,swap in/swap out这里的代价比较大,相比数据一直放在内存里面,多了读磁盘的操作,而磁盘IO代价太大

    The Android Runtime (ART) and Dalvik virtual machine use paging and memory-mapping (mmapping) to manage memory. This means that any memory an app modifies—whether by allocating new objects or touching mmapped pages—remains resident in RAM and cannot be paged out. The only way to release memory from an app is to release object references that the app holds, making the memory available to the garbage collector. That is with one exception: any files mmapped in without modification, such as code, can be paged out of RAM if the system wants to use that memory elsewhere.

    这意味着无论是分配一个新的对象或者touching mmapped pages , app的内存发生变化之后都会停留在RAM中,不会被paged out (换页到硬盘)。唯一释放内存的方法就是释放app持有的对象,让内存可以被GC(垃圾回收)。

    有一点是例外的:如果系统想在其他地方使用该内存(切换app ,内存不足),同时采用mmapping映射到内存的代码文件(.odex)、资源文件(zipalign后的resource)没有发生改变,这部分内存就会被paged out 。

    垃圾回收GC (Garbage collection)

    Android Runtime (ART) and Dalvik virtual machine

    Dalvik: Dalvik是Google公司自己设计用于Android平台的Java虚拟机它可以支持已转换为 .dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。执行的是字节码,它是依靠Just-In-Time (JIT)机制去解释字节码

    ART:即Android Runtime,google为了替代Dalvik专门为Android研发的。Android KK为开发者推出,L版本正式上线。比替代品更高效省电,执行的是本地机器码,依靠Ahead-Of-Time (AOT)机制

    Android Runtime内存堆划分

    what’s gc

    A managed memory environment, like the ART or Dalvik virtual machine, keeps track of each memory allocation. Once it determines that a piece of memory is no longer being used by the program, it frees it back to the heap, without any intervention from the programmer. The mechanism for reclaiming unused memory within a managed memory environment is known as garbage collection. Garbage collection has two goals: find data objects in a program that cannot be accessed in the future; and reclaim the resources used by those objects.

    ART 或者 DVM 会一直跟踪每一块内存的分配, 一旦发现某一块内存没有被使用,就会自动返还给内存堆。在管理内存环境中回收没有用内存堆机制,称之为垃圾回收(GC )。
    GC有两个目的:
    1. 发现程序中在未来不会被访问到的数据对象
    2. 回收那些被对象使用的资源

    generation

    Android’s memory heap is a generational one, meaning that there are different buckets of allocations that it tracks, based on the expected life and size of an object being allocated. For example, recently allocated objects belong in the Young generation. When an object stays active long enough, it can be promoted to an older generation, followed by a permanent generation.

    Android的内存堆是一块大的内存空间,基于可预期的存活周期和分配的大小,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。

    新生代:Young Generation,主要用来存放新生的对象。
    老年代:Old Generation或者称作Tenured Generation,主要存放应用程序生命周期长的内存对象。

    /永久代:在JDK1.6版本之后,永久代就要被取消掉了,只留下年轻代和老年代。(方法区,不属于java堆,另一个别名为“非堆Non-Heap”但是一般查看PrintGCDetails都会带上PermGen区)是指内存的永久保存区域,主要存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域. 它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用会加载很多Class的话,就很可能出现PermGen space错误。/

    堆大小 = 新生代 + 老年代。其中,堆的大小可以通过参数 –Xms、-Xmx 来指定。
    默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小。老年代 ( Old ) = 2/3 的堆空间大小。其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 from 和 to,以示区分。
    默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小。
    JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。
    因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

    Generation

    性能影响

    Each heap generation has its own dedicated upper limit on the amount of memory that objects there can occupy. Any time a generation starts to fill up, the system executes a garbage collection event in an attempt to free up memory. The duration of the garbage collection depends on which generation of objects it's collecting and how many active objects are in each generation.

    堆的每一个区域的对象占据的内存都有上限 ,只要某一代开始占满,系统就会执行一个GC事件尝试去释放内存。触发暂停的时间依赖于在某代和有多少可回收的对象

    Even though garbage collection can be quite fast, it can still affect your app's performance. You don’t generally control when a garbage collection event occurs from within your code. The system has a running set of criteria for determining when to perform garbage collection. When the criteria are satisfied, the system stops executing the process and begins garbage collection. If garbage collection occurs in the middle of an intensive processing loop like an animation or during music playback, it can increase processing time. This increase can potentially push code execution in your app past the recommended 16ms threshold for efficient and smooth frame rendering.

    即使GC是相当快的,但仍然会影响到app的性能。你不能用代码来直接控制gc事件的发生。系统有一套执行GC的标准,符合条件后,系统会停止执行中的进程,开始GC。如果GC发生在一个循环处理的过程当中(动画或者音乐回放),会增加其处理的时间。这个增加的时间可能会影响app的帧数,导致达不到推荐的16ms閾值。(Android 屏幕 每秒刷新60hz,相当于16ms渲染,超过16ms,将在下次16ms中刷新,故产生卡顿。)

    Additionally, your code flow may perform kinds of work that force garbage collection events to occur more often or make them last longer-than-normal. For example, if you allocate multiple objects in the innermost part of a for-loop during each frame of an alpha blending animation, you might pollute your memory heap with a lot of objects. In that circumstance, the garbage collector executes multiple garbage collection events and can degrade the performance of your app.

    你的代码流可能会让GC事件频繁发生,执行时间变长。例如,在每一帧的混合动画中,在for循环的内部处理多个对象,这样可能就会污染到内存堆。在这种场景,GC会执行多次,这样就会降低app的性能。

    For more general information about garbage collection, see Garbage collection.

    Sharing Memory(内存共享)

    • 每一个app进程都是由Zygote fork 出来的,当系统启动时zygote开启,加载framework code和resource(如activity theme) 。 然后系统会fork zygote 开启一个新的app进程,在此进程中加载运行app的代码。这个模式允许大部分分配到framework code 跟 resource的RAM pages 能够跨进程共享。

    • 大部分到静态数据是采用mmapped 到进程内,mmapped允许进程间共享数据,也允许paged out 出RAM 。
      静态数据包括:
      1、 Dalvik code(将直接mmapping的放置在 预连接的.ode文件)
      2、app resources(设计成结构后能mmapp 的resource table,apk中的对齐后的zip实体,也是zipalign app)
      3、传统的项目元素(如.so文件中的native code)

    • 在很多地方,Android通过显式的分配共享内存区域(ashmem或gralloc) 来跨进程共享 相同的动态RAM。例如:window surfaces在app和screen compositor之间共享内存,cursor buffer在content provider和client之间共享内存。

    分配与回收 (Allocating and Reclaiming App Memory)

    app进程的Dalvik heap被限制在 single virtual memory range(单独一块的虚拟内存范围内),heap size可以增加,但是系统定义了上限。

    heap使用的虚拟内存 不等于 使用的物理内存大小。当监测 APP的heap时,Android统计一个数值被称为Proportional Set Size(PSS),PSS包含与其他进程共享的 dirty and clean pages,但共享内存只统计 一个app所占RAM比例的大小(如:3个app共享15个pages,则PSS中共享内存为5个pages)。系统认为PSS是物理内存的footprint(印记,也就是消耗了,像碳排放印记)。
    Dalvik堆栈不计算堆栈的逻辑大小,也就是Android不会对heap进行碎片整理来释放堆栈的空间。android只能通过删除堆栈的尾部不用的空间来减少堆栈的大小,但这并不是说物理内存不能被压缩(不能从堆栈中间删除数据)。

    GC回收器会浏览堆栈,并把堆栈中不用的页空间回收到内核通过madvise这个函数(这个函数可以对映射的内存提出使用建议,从而提高内存)。所以,成对分配与回收大块的数据可以全部(几乎全部)回收物理内存。然而用同样的方式回收小块数据的效率就低了。因为小块数据可能还被其他的使用,且引用还没有释放。

    限制App内存(Restricting App Memory)

    为了维护多任务的运行,android 为每个应用设置了一个硬性的内存堆栈限制,一旦应用使用的内存超过这个值就会报OUtOfMemoryError的错误。

    一些情况下,你的应用可能需要知道当前运行系统环境对堆栈内存的限制大小是多少,从而做出合理的操作,不如缓存多少数据,使用高清图片还是普通图片。可以通过getMemoryClass()的方式获取这个限制的大小,详见Check how much memory you should use

    app切换( Switching apps)

    当用户切换应用的时候,别切换到后端的应用使用的内存并没有被切换或者删除,进程会被缓存到LRU缓存中。比如用户首先启动了一个应用,系统会创建一个进程,当用户离开这个应用,这个进程并没有退出,而是别缓存到LRU缓存中,所以当用户再次返回到这个应用的时候,能更快速更高效的启动,从而应用切换更快。

    如果你的应用被缓存到LRU中,还在不断的申请内存或不释放占用的(不需要的)内存,这会影响到系统的性能,所以,当系统进行到内存低可用的时候,会从LRU缓存中最早一个被缓存的程序开始移除(释放进程暂用的资源),同时也会考虑应用所暂用的内存的大小。为了能让你的应用尽可能长的在LRU中缓存,可以更加以下建议释放引用的资源。

    更多关于系统入会缓存应用到LRU已经如何移除应用,参考Processes and Threads

    Android内存管理机制详解 - CSDN博客
    Android 开发进阶之『清除应用中的内存泄漏』 - 简书
    谈谈Android的内存管理机制
    Overview of Android Memory Management | Android Developers
    Android 性能优化 内存优化 How Android Managers Memory - baiiu - CSDN博客
    Java堆内存 - ImportNew
    http://blog.csdn.net/zhjali123/article/details/75270571
    http://blog.csdn.net/z8711042/article/details/18665933

    相关文章

      网友评论

          本文标题:android内存管理

          本文链接:https://www.haomeiwen.com/subject/frabgttx.html