Android内核读书笔记(3)—Android内存管理

一、应用程序关闭而不退出
        1.关闭-->仅仅是窗口不可见,但其对应的进程还存在
        如果后台有许多进程存在的话,只会占用内存空间,而不会降低前台进程的运行速度,为什么?
        
        每个应用程序主体--->ActivityThread,该类初始化后会进入消息循环(Looper.loop)当中
        
        以后则靠消息机制,有消息就处理消息,没有消息就sleep
        
        在queue.next方法中会从消息内部取出消息,如果没有消息则会sleep当前的线程,直到有新消息到来时会唤醒next()方法

        queue.next()方法被唤醒的三种情况:
            a.定时器中断
                操作系统向定时器发送一个任务,该任务会向looper发送一个消息

            b.用户按键消息
                wms把用户按键消息发送到looper主线程

            c.Binder中断
                Binder-->Linux的一个驱动
                应用程序中可以包含一个binder对象---->     Binder驱动接收binder消息派发给客户端binder对象--->binder消息处理中会向looper主线程发送一个消息

        2.Android与Linux的配合
               Android官方文档指出Activity占用的内存只有在内存不够用的时候才会被回收,而内存是否够用属于Linux内核管理,Ams并不知道
        
                Ams运行在java环境,当java环境内存低时会抛出oom异常,但这并不代表应用程序内存就很低,因为
                    i.应用程序与Ams运行在两个独立的java虚拟机中,应用程序申请内存并不会通知Ams
                    ii.java虚拟机运行时都有自己独立的内存空间
                综上,单纯的Ams是无法知道系统内存是否低的

                什么是系统内存低?
                    Android中并未采用虚拟内存,故应用程序使用的内存大小取决于物理内存的大小,系统内存低就意味着物理内存所剩无几
        
                Android中运行了一个OOM 进程--->系统启动时会向linux内核注册为一个OOM Killer--->当内存低时linux内核的内存管理模块会通知oom killer---->
                oom killer会根据各种规则进行内存释放

                Android中的oom killer进程仅适用于Android应用程序,Ams会把每一个应用程序的oom_adj值告诉给oom killer,该值类似于linux的nice值,在-16到15之间,
                值越小说明越重要  

        3.各种关闭程序的过程
        
                    i.startActivity开始
                        startActivity--->暂停当前Activity--->Ams收到Binder消息--->Ams.completePaused--->将activity添加进mStoppingActivities列表  
                        --->目标Activity启动,向Ams发送请求内存回收的消息--->Ams.activityIdleInternal--->调用stopActivityLocked,处理mStoppingActivities中的
                        activity--->ActivityThread.stop---->Ams.activityStopped--->trimApplications
                    
                    ii.按back键
                        finishActivityLocked--->startPausingLocked--->Ams.completePaused--->finish状态为true--->finishingActivityLocked

                    iii.向Ams发送Idle消息
                        activityIdleInternal--->trimApplication

                    iv.释放内存的3个地点
                        a.在Ams中进行
                        b.在OOMKiller中进行,Ams告诉oomkiller各个应用进程的优先级,然后oomkiller会调用linux的内核中的内存管理根据优先级杀掉进程
                        c.应用进程本身之中,通知ActivityThread.scheduleLowMemory和ActivityThread.processInBackground
        

        4.释放内存详解
            a.activityIdleInternal被调用的各种原因
                 Android内核读书笔记(3)—Android内存管理_第1张图片
                i.handleResumeActivity--->addIdleHandler(new Idler())--->Idler.queueIdle--->Ams.activityIdle
                ii.HistoryRecord.windowVisible--->发送IDLE_NOW_MSG--->Ams.activityIdle
                iii.Ams.completePausedLocked
                    
                iv.completeResumeLocked中发生超时--->发送IDLE_TIMEOUT_MSG--->activityInternal
                v. activityInternal方法的内部实现
                    1).通知所有需要回收的客户线程(mProcessesToGc中的进程)进行内存回收
                    2).取出 mStoppingActivities 列表中的内容,并存放到临时列表stops 中,再取出mFinishigActivities
列表中的内容,并存放到临时列表finishes 中,然后删除原有的记录
                         Android内核读书笔记(3)—Android内存管理_第2张图片
                    3).对stops的activity列表进行处理,改处理过程中为什么要判断finish是否为true?
                        因为按下“Back”键后,finishing 状态true,接着在completePaused()
                        中调用到了finishCurrentActivity ( 3 个参数)函数, 该函数中则会把指定的Activity 添加到
                        mStoppingActivities 列表中,显然,此时该Activity 的finishing 状态为true
                        
                        stopActivtyLocked通知目标进程ActivityThread调用onStop
                    4).接着对finish列表中的对象进行处理
                        
                    ps:以上2、3、4步并没有对客户进程进行主动的内存回收,仅仅是针对不同状态通知
                         客户进程执行不同的回调而已
                    5).调用trimApplications,真正意义上的对内存进行回收
        
                vi. trimApplications方法内部执行原理
                    1).删除mRemovedProcesses中的进程
                                mRemovedProcesses进程的来源?
                                   1.1 当某个进程crash
                                   1.2 当某个程序的UI 线程在5 秒之内没有响应时,系统会弹出一个ANR 对话框,此时如
                                         果用户选择强制关闭,该进程就会被添加到该列表
                                   1.3 当 程 序 员 调 用 AmS 提供的killBackgroundProcess() 方法时 
                                   1.4 当系统启动时,AmS 的systemReady()方法中,如果发现启动了非persistent 类型的应
                                         用进程,则把这些进程添加到列表
                     2).调用updateOomAdjLocked方法,告诉OOM Killer 指定进程的优先级,若底层的linux系统包含OOMkiller,
                         则返回true,否则返回false
                     3).若上一步返回false,则优先杀死后台activity
                     4).经过以上三步后,若此时的activity数量依然超过阀值,则继续销毁满足一下三个条件的activity:
                            4.1 activity已经stop了,但是没有finish
                            4.2 不可见的activity
                            4.3 不是persistent类型的

                vii.updateOomAdjLocked(ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP)  告诉OOM 进程指定应用进程的优先级
                      a).computeOomAdjLocked计算当前进程的adj值 Android内核读书笔记(3)—Android内存管理_第3张图片
                    1.估算指定线程的oom_adj值
                        
                        1.1 如果该进程是TOP_APP
                                
                        1.2 如果进程中包含instrumentationClass
                                
                        1.3 如果包含正在执行的receiver对象
                                 Android内核读书笔记(3)—Android内存管理_第4张图片
                        1.4 包含正在执行的service对象
                                
                        以上几步都是最高优先级
            
                        1.5 如果包含前台服务对象
                                
                    
                        1.6 如果进程正在被用户强制调到前台
                                
                        1.7 如果为home进程
                                 Android内核读书笔记(3)—Android内存管理_第5张图片
                        1.8 如果当前activity的数目大于0并且visible
                                 Android内核读书笔记(3)—Android内存管理_第6张图片
                        1.9 如果是空进程
                                 Android内核读书笔记(3)—Android内存管理_第7张图片
                        综上,以上几步得到的adj值是一个rawAdj,也就是源码中的unlimited,即无限制条件下应有的优先级值
                                 Android内核读书笔记(3)—Android内存管理_第8张图片

                    2.对于service和provider的adj值
                        2.1 如果是备份进程
                                 Android内核读书笔记(3)—Android内存管理_第9张图片
                        2.2 处理当前进程中非前台service(即该service不属于前台进程,也没有和前台进程交互)
                            2.2.1 该app所包含的service的优先级大于前台进程并且所在调度组为背景非交互                                    
 
                            2.2.2 该service被请求启动过,并且没超过打击时间(30分钟),优先级设为SECONDARY_SERVER_ADJ
                                        
                            2.2.3 处理和该service连接的客户端,并根据其客户端的优先级调整其service的优先级,如果客户端是该进程本身,不作处理
 
                                    
                            2.2.4 如果是BIND_AUTO_CREATE方式创建的service
                                      Android内核读书笔记(3)—Android内存管理_第10张图片
                        2.2.5 判断客户连接对应的activity
                                 Android内核读书笔记(3)—Android内存管理_第11张图片
 
                    2.3. 处理provider的情况(与service基本相同)
                        
 
                    2.4 查看上述的adj值是否超过系统给定的对大值
                            
 
                    
                b) 1.判断当前app是否需要从前台切换到后台
                        
 
                    2. 真正的adj值已改变
                         Android内核读书笔记(3)—Android内存管理_第12张图片
 
                    3. 所在调度组发生变化
                    
                       Android内核读书笔记(3)—Android内存管理_第13张图片
            viii.判断当前app的curAdj值
                
                Android内核读书笔记(3)—Android内存管理_第14张图片
            viv.Ams内部内存回收潜规则(oom killer)

            vv.scheduleAppGcLocked通知指定的app对象进行内存回收
                
                    Android内核读书笔记(3)—Android内存管理_第15张图片
                     Android内核读书笔记(3)—Android内存管理_第16张图片
                    performAppGcsIfAppropriateLocked :处理GC_BACKGROUND_PROCESSES_MSG消息
                    
                        canGcNowLocked:判断是否适合进行回收
                        
                        即:
                            .当前没有正在执行的Broadcastreceiver
                            .当前处于sleep状态或者正在执行的activity处于idle状态

                        performAppGcsLocked
                        
                        performAppGcLocked
                         Android内核读书笔记(3)—Android内存管理_第17张图片
 
                     ps:当客户进程启动失败是会将app.reportLowMemory设置为true
                    
                    ActivityThread.scheduleLowMemory
                        
 
                    ActivityThread.handleLowMemory处理上面的方法
                     Android内核读书笔记(3)—Android内存管理_第18张图片    
                    
                    processInBackground方法
                                
                            
                ps: processInBackground方法只会回收Binder相关的内存

        5.如何理解activity
            a. Activity并不对应一个应用程序,ActivityThread才对应一个应用程序
            b. 默认activity会添加一个窗口,但实际上可以修改,使其不添加任何窗口
            c. 在系统内存低的时候会释放调显存
                        

你可能感兴趣的:(Android内核读书笔记(3)—Android内存管理)