美文网首页
移动开发的内存管理

移动开发的内存管理

作者: 一叶也知秋 | 来源:发表于2017-07-30 22:15 被阅读0次

    移动系统对资源的限制和要求

    移动操作系统现对于PC端的一个首要特点就是资源有限,比如内存、电池、网络的不确定等等,这些资源相对于PC端来说都很有限,当然对于发展到今天的移动端设备来说,这个已经不算是一个大问题了,不过,在移动端开发中,针对资源有限的问题都是一个不得不正视的问题。本文主要针对内存这一块进行阐述,针对移动网络的特点、电池优化的问题、有后续系列阐述文章。

    移动操作系统的几个主要特点

    • 移动设备需要便携,所以需要携带电池,需要专门的电池管理,这一点,笔者当年首次学习Symbian系统时却有体会;
    • 移动设备通常情况下,屏幕比较小,但是需要展示的信息一点也不少,所以,就需要在界面设计以及交互设计上(UI UE)需要更多的想象力,需要更好的更人性化的设计,需要面对的情况也更复杂;
    • 由于移动设备的大部分都需要电池供电,所以,在选择CPU时,也就必须考虑好CPU的功耗问题,复杂指令集的基本不建议在考虑之列。
    • 同样由于电池所限,使用的内存(memory)和存储相对于PC桌面系统来说都相当受限制。
    • 由于移动设备资源所限,大部分移动设备操作系统,都需要分时复用来管理所有的需要运行的程序(通常叫App)。
      • 现阶段流行的移动操作系统主要是ios和android,其中大部分程序都运行在后台情况下,都由系统层面管理App所占用的各类资源,比如内存,当程序后台运行时,大部分情况下内存都会被回收。
      • 移动操作系统一般情况下都会限制每个应用所消耗的资源总量。
      • 作为App开发者,管理好自身App所消耗的资源是一个应尽的义务。
    • 管理

    Android内存管理机制浅析

    Android是2007年Google在收购基础上推出的基于Linux操作系统的开源移动操作系统,该平台由操作系统、中间件、用户界面和应用软件组成。

    Android的系统架构和其操作系统一样,采用了分层的架构。[ Android结构

    Android结构

    从架构图看,Android分为四个层,分别是应用程序层、应用程序框架层、系统运行库层和Linux层。

    Android应用开发

    在Android平台上开发应用程序,包括java 和C++(for Native)。

    android平台的内存管理

    一般情况下(多进程例外)每个应用都会由系统分配一个进程(zygote)资源。这段Android代码可以获取当前进程的内存情况。

            ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
            int memClass = activityManager.getMemoryClass();
            int maxClass = activityManager.getLargeMemoryClass();
    

    任何一个进程最多可以获取的内存资源时有限的。

    内存优化思路

    强引用与弱引用

    • 在一个Activity生命周期中,其中所有定义的变量的生命周期都和Activty保持一致,如果用强引用的话,那么变量所指向的内存和Activity生命周期保持一致,但是在很多情况下,从逻辑上这个成员变量已经不需要了,由于强引用其所指向的内存区域也保持一样的什么周期,有点得不偿失。
    • 这种情况下,可以选择弱引用,所谓弱引用就是指其指向的内存区域,在内存比较紧张的时候可以被GC。这样就可以减少内存的使用。
        WeakReference<ForeEngine> mWeakForeEngine;
        ForeEngine  mForeEngine;
    

    其中:

    • mForeEngine是强引用,mWeakForeEngine是弱引用
    • mWeakForeEngine指向的内存在mWeakForeEngine运行过程中可能会被回收

    弱引用的初始化

         mWeakForeEngine  = new WeakReference<ForeEngine>(foreEngine) ;
    

    弱引用的使用

          ForeEngine foreEngine = mWeakForeEngine.get();
         if(foreEngine == null) {
         //  todo
         }
    

    关注内存大户Bitmap

    待续

    Android内存管理原理简析

    Java虚拟机模型

    JVM内存模型,java虚拟机在构建RunTime运行时数据内存分配,
    内存主要分为方法区,虚拟机栈,本地方法栈,堆,PCR程序计数器。
    

    JVM内存模型示意

    Android的改进

    - 寄存器和栈的区别
         * JVM虚拟机基于栈,DVM基于寄存器。*
    - Dalvik和java虚拟的区别  dex class的区别
    -  dalvik art的改进
       android虚拟机都使用页式和memory mapping方式进行内存管理,虚拟机分配并决定了内存的生命周期,并且使用GC(*garbage collection*)来回收已分配但是不再使用的内存片段,GC的主要工作主要分为两个部分:
         1)找到内存中不再使用的数据片段
         2)回收这些资源
       分配内存资源主要是分代管理,刚刚分配的内存区域叫Young Generation。
       对象在Young Generation时间比较长之后,就会被划到Older Generation,还有一个permanent generation。
        尽管内存回收的速度较快,但是由于会在程序运行过程中的停下执行GC,不可避免的的会影响程序的运行,一旦GC边界条件被触发,系统就会停止当前进程,开始GC。
        关于GC的详细机制详见,ref:
    - Android Runtime(ART)的进一步改进措施
        1) ART中暂停次数相比于Dalvik有减少,从两次减为一次;
        2)ART GC 一样有暂停中断,不一样之处在于,ART在有些阶段比如引用过程,sytem sweeping过程,等阶段中可以并发的执行GC。
    

    DVM算法简析

    • 程序运行过程中,不断申请新的对象消耗内存,直到用完所有,然后创建新的对象需要内存的时候,暂停运行,出发GC 回收,器原理就是从GC Roots开始,将整个内存遍历,保留所有被直接以及间接用的内存区域,余下的被回收。
      该算法可以解决内存的问题,释放内存。
    • 但是缺点一样存在,1 从GC Roots开始的遍历是一个递归调用,这个过程本身会消耗很多资源,一方面在内存不多时候消耗内存递归,另一方面,如果遍历非常深的话,消耗的时间资源也很明显。所有后来的android系统优化了这个过程,另开启线程逐步释放内存,尽量不影响程序的正常运行。也就是逐步GC,还有一个叫CMS(concurrent mark sweep)。
    • 下面是代码

      1 启动VM

    \dalvik\vm\Init.cpp
    /*
    * VM initialization.  Pass in any options provided on the command line.
    * Do not pass in the class name or the options for the class.
    *
    * Returns 0 on success.
    */
    std::string dvmStartup(int argc, const char* const argv[],
    bool ignoreUnrecognized, JNIEnv* pEnv)
    

    其中 启动的内容很多,有兴趣的可以参考源代码。

    2 GC 启动

    在main heap上采用mmap管理内存。
    dalvik\vm\alloc\alloc.cpp

    /*
    * Initialize the GC universe.
    *
    * We're currently using a memory-mapped arena to keep things off of the
    * main heap.  This needs to be replaced with something real.
    */
    bool dvmGcStartup()
    {
    dvmInitMutex(&gDvm.gcHeapLock);
    pthread_cond_init(&gDvm.gcHeapCond, NULL);
    return dvmHeapStartup();
    }
    

    3 GC heap启动

    dalvik\vm\alloc\Heap.cpp
    初始化GC heap 并建立VM card table。

    /*
    * Initialize the GC heap.
    *
    * Returns true if successful, false otherwise.
    */
    bool dvmHeapStartup()
    {
    GcHeap *gcHeap;
    if (gDvm.heapGrowthLimit == 0) {
    gDvm.heapGrowthLimit = gDvm.heapMaximumSize;
    }
    gcHeap = dvmHeapSourceStartup(gDvm.heapStartingSize,
    gDvm.heapMaximumSize,
    gDvm.heapGrowthLimit);
    if (gcHeap == NULL) {
    return false;
    }
    gcHeap->ddmHpifWhen = 0;
    gcHeap->ddmHpsgWhen = 0;
    gcHeap->ddmHpsgWhat = 0;
    gcHeap->ddmNhsgWhen = 0;
    gcHeap->ddmNhsgWhat = 0;
    gDvm.gcHeap = gcHeap;
    /* Set up the lists we'll use for cleared reference objects.
    */
    gcHeap->clearedReferences = NULL;
    if (!dvmCardTableStartup(gDvm.heapMaximumSize, gDvm.heapGrowthLimit)) {
    LOGE_HEAP("card table startup failed.");
    return false;
    }
    return true;
    }
    

    4

    dalvik\vm\alloc\HeapSource.cpp
    为了不和zygote heap的内存发生交集,在首次fork之前调用它,这个仍然会有一些造成小片段内存的问题存在

    /*
    * This is called while in zygote mode, right before we fork() for the
    * first time.  We create a heap for all future zygote process allocations,
    * in an attempt to avoid touching pages in the zygote heap.  (This would
    * probably be unnecessary if we had a compacting GC -- the source of our
    * troubles is small allocations filling in the gaps from larger ones.)
    */
    bool dvmHeapSourceStartupBeforeFork()
    {
    HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
    HS_BOILERPLATE();
    assert(gDvm.zygote);
    if (!gDvm.newZygoteHeapAllocated) {
    /* Ensure heaps are trimmed to minimize footprint pre-fork.
    */
    trimHeaps();
    /* Create a new heap for post-fork zygote allocations.  We only
    * try once, even if it fails.
    */
    ALOGV("Splitting out new zygote heap");
    gDvm.newZygoteHeapAllocated = true;
    return addNewHeap(hs);
    }
    return true;
    }
    

    相关文章

      网友评论

          本文标题:移动开发的内存管理

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