美文网首页
温故---Android 线程、进程老生常谈

温故---Android 线程、进程老生常谈

作者: Joker_Lee | 来源:发表于2020-04-27 12:04 被阅读0次

    进程&线程

    首先明确:
    程序--->指计算机能够识别和执行的指令及数据静态文件,比如Windows平台的exe文件;
    进程--->程序执行必须要系统分配资源创建实体之后才能运行,这个创建运行的实体即为计算机为了管理描述而进行抽象的概念--进程;进程是系统资源分配调度的单位

    通常分配给进程的资源包括独立的地址空间、寄存器、文件I/O等
    在面向线程设计的系统(如当代多数操作系统、Linux 2.6及更新的版本)中,进程本身不是基本运行单位,而是线程的容器。(维基百科)

    线程--->引入线程的系统,通常进程本身不参与实际任务执行所以需要真正执行任务的单元即线程,同一进程内的线程共享该进程的资源,线程只拥有自身的栈、PC寄存器和局部变量存储 线程是任务调度执行的最小单位

    区别

    1.进程是操作系统分配资源的单位,而线程是CPU任务执行和调度的单位;
    2.进程是线程的容器,一个进程拥有一个或多个线程;
    3.进程间的资源相互独立,进程间只能通过IPC进行通信,一个进程crash不会影响到其它进程;
    4.同进程下的所有线程共享该进程的资源,线程间通信更方便但是付出代价保证线程安全。

    并发:同一时间段,多个任务都在执行 (单位时间内不一定同时执行),分时调度(典型的调度方法:时间片轮转调度,每个任务可以得到一定的时间片执行,用完时间片则切换给另外的任务)

    并行:单位时间内,多个任务同时执行(通常为多CPU或单CPU多核系统,允许多任务同时在不同CPU或不同核同时执行)

    Android平台的进程&线程

    Android基于Linux内核而又选择使用Java作为应用开发语言,周知的Java之所以应用的这么广泛--->由于JVM的存在隐藏的不同平台硬件的差异,java程序都运行在JVM中。

    //从一句最简单的执行java程序的指令,可以看到需要先调用java命令起一个jvm实例,然后jvm的类加载器将test.class加载解析运行
    javac test.java && java test 
    

    Android看中了java的跨平台特性,所以Android应用程序也是不可避免的跑在VM上,当Java程序或者Android应用程序运行的时候没有一个虚拟机是无辜的。

    Google公司自己设计实现了用于Android平台的Dalvik虚拟机以及对应的dex格式,适合于内存和处理器速度有限的系统。以及后续由使用ART替代了Dalvik。(三类VM之间的具体差异参考:Android开发——JVM、Dalvik以及ART的区别

    每一个Android应用程序(进程)都运行在一个DVM or ART虚拟机实例中, Dalvik虚拟机进程就是本地操作系统进程,也就是Linux进程,区别在于前者运行有一个Dalvik虚拟机实例。这个虚拟机负责对象的生命周期、堆栈内存管理、垃圾回收&线程管理等。
    具体分析可以看:https://blog.csdn.net/sauphy/article/details/50507593

    Android的线程基本就是Thread、Handler、MessageQueue&Looper这相爱相杀的一套。

    Android的多进程

    多进程的使用方式:

    AndroidMantifest.xml中的activity、service、receiver和provider均支持android:process属性; application元素也支持android:process属性,可以修改应用程序的默认进程名(默认值为包名)

    开启私有进程:android:process=":processName",以冒号开头,最终进程名为packageName:processName com.baidu.searchbox:bdservice_v1

    开启全局进程:android:process="com.example.processtest.remote"
    其他应用通过设置相同的ShareUID可以和它跑在同一个进程达到文件数据资源共享的目的

    使用方法很简单,但是首先来聊聊为啥要使用多进程?
    笔者个人总结可能有这么些理由:

    1.进程或者说应用保活,更合适的说法是让自己的应用有合适的进程优先级;
    2.消耗内存的大的应用更合理的使用资源;
    3.超级App(包含很多功能模块的应用)合理使用更多资源并且增强应用的稳定性

    让应用拥有合适的进程优先级

    在Android生态野蛮生长期,特别是国内经常Native守护进程的方案经常被用来作后台保活;在后续5.0之后Google慢慢整改收回多数权限封堵漏洞,这种情况得以改善。
    笔者更倾向于使用多进程,设定合适的优先级既能实现自己应有的合理保活又符合Google的规范保证Android的生态健康。

    1.前台进程
    2.可见进程
    3.服务进程
    4.后台进程
    5.空进程

    规范使用进程优先级:https://blog.csdn.net/qq_27489007/article/details/54377655

    更合理的分配使用资源&稳定性

    为了保证系统资源的平衡,Android手机厂商出厂会调整设定每个应用(进程)的堆内存上限ActivityManager.getMemoryClass()

        public int getMemoryClass() {
            return staticGetMemoryClass();
        }
    
        /** @hide */
        static public int staticGetMemoryClass() {
            // Really brain dead right now -- just take this from the configured
            // vm heap size, and assume it is in megabytes and thus ends with "m".
            String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "");
            if (vmHeapSize != null && !"".equals(vmHeapSize)) {
                return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
            }
            return staticGetLargeMemoryClass();
        }
    
        /**
         * Return the approximate per-application memory class of the current
         * device when an application is running with a large heap.  This is the
         * space available for memory-intensive applications; most applications
         * should not need this amount of memory, and should instead stay with the
         * {@link #getMemoryClass()} limit.  The returned value is in megabytes.
         * This may be the same size as {@link #getMemoryClass()} on memory
         * constrained devices, or it may be significantly larger on devices with
         * a large amount of available RAM.
         *
         * <p>This is the size of the application's Dalvik heap if it has
         * specified <code>android:largeHeap="true"</code> in its manifest.
         */
        public int getLargeMemoryClass() {
            return staticGetLargeMemoryClass();
        }
    
        /** @hide */
        static public int staticGetLargeMemoryClass() {
            // Really brain dead right now -- just take this from the configured
            // vm heap size, and assume it is in megabytes and thus ends with "m".
            String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");
            return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length() - 1));
        }
    

    厂商出厂在/system/build.prop设定了:

    dalvik.vm.heapstartsize=16m //应用默认初始堆大小
    dalvik.vm.heapgrowthlimit=192m //最大堆增长上限,通常对应最大能使用的内存值
    
    <application
            android:largeHeap="true">
    dalvik.vm.heapsize=512m //若在Manifest声明了largeHeap="true" 则以这个值为最大内存上限
    
    $adb shell getprop dalvik.vm.heapgrowthlimit
    $adb shell getprop dalvik.vm.heapsize
    $adb shell getprop dalvik.vm.heapstartsize
    

    关于应用最大内存设定可参考文章:https://www.dazhuanlan.com/2020/02/28/5e58976696bfa/

    由于进程最大内存使用是有上限的,所以若要使用开发一些内存消耗占用比较的应用,比如大图浏览编辑等;使用额外的进程可以在不影响正常业务进程的情况下获得多的内存来使用并且该进程异常crash也不会影响其它业务进程。

    多进程的引发的问题

    上面说了多进程使用可以获得的一些优势,那么需要付出的代价呢?

    1.进程间资源独立隔离,那么单例、静态变量这些都会失效;
    2.Application onCreate可能会调用多次;
    3.进程间隔离,需要使用IPC才能通信,而不是线程间的Handler发发消息就能搞定了;
    4.多进程下Sharepreference等文件读写并不安全

    总之需要权衡实际需求来进行选择是否需要使用多进程,而不是为了多进程而多进程。

    参考

    1.https://blog.csdn.net/luoshengyang/article/details/8852432
    2.https://blog.csdn.net/fanleiym/article/details/83894399

    相关文章

      网友评论

          本文标题:温故---Android 线程、进程老生常谈

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