xhj-records

Android中的进程和线程(一)(转载/整理)

先引用一段关于进程与线程之间关系的描述<——多线程编程的基础知识点

     在进程中,有些程序流程块是可以乱序执行的,并且这个代码块可以同时被多次执行。实际上,这样的代码块就是线程体。线程是进程中乱序执行的代码流程。当多个线程同时运行的时候,这样的执行模式成为并发执行。”

    下面我以一个日常生活中简单的例子来说明进程和线程之间的区别和联系:
       
     这副图是一个双向多车道的道路图,假如我们把整条道路看成是一个“进程”的话,那么图中由白色虚线分隔开来的各个车道就是进程中的各个“线程”了。

     ①这些线程(车道)共享了进程(道路)的公共资源(土地资源)。

     ②这些线程(车道)必须依赖于进程(道路),也就是说,线程不能脱离于进程而存在(就像离开了道路,车道也就没有意义了)。

     ③这些线程(车道)之间可以并发执行(各个车道你走你的,我走我的),也可以互相同步(某些车道在交通灯亮时禁止继续前行或转弯,必须等待其它车道的车辆通行完毕)。

     ④这些线程(车道)之间依靠代码逻辑(交通灯)来控制运行,一旦代码逻辑控制有误(死锁,多个线程同时竞争唯一资源),那么线程将陷入混乱,无序之中。

     ⑤这些线程(车道)之间谁先运行是未知的,只有在线程刚好被分配到CPU时间片(交通灯变化)的那一刻才能知道   

再引用一段关于JVM中进程与线程的描述:进程、线程与JVM、CLR

     Java编写的程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。

     每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行的。JVM找到程序程序的入口点main(),然后运行main()方法,这样就产生了一个线程,这个线程称之为主线程。当main方法结束后,主线程运行完成。JVM进程也随即退出。

     操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段时间(不一定是均分),然后在每个进程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的

     如下图所示:

    

然后就是今天的主题Android中的进程和线程:Android API Guides

其译文摘自http://blog.csdn.net/nkmnkm/article/details/7202300

     When an application component starts and the application does not have any other components running, the Android system starts a new Linux process for the application with a single thread of execution. By default, all components of the same application run in the same process and thread (called the "main" thread). If an application component starts and there already exists a process for that application (because another component from the application exists), then the component is started within that process and uses the same thread of execution. However, you can arrange for different components in your application to run in separate processes, and you can create additional threads for any process.
    当一个应用的组件开始运行,并且这个应用没有其它的组件在运行,系统会为这个应用启动一个新的Linux进程,这个进程只有一个线程.默认情况下,一个应用的所有组件都运行在一个进程和线程(主线程)中.如果一个应用的进程开始运行,并且已经存在这个应用的线程了(因为有这个应用程序的另一个组件已经运行了),于是这个组件就会在这个已有的进程中启动并且运行在同一个线程中.然而,你完全可以安排不同的组件运行于不同的进程,并且你可以为任何程序创建另外的线程.

     By default, all components of the same application run in the same process and most applications should not change this. However, if you find that you need to control which process a certain component belongs to, you can do so in the manifest file.
     The manifest entry for each type of component element—<activity>, <service>, <receiver>, and <provider>—supports an android:process attribute that can specify a process in which that component should run. You can set this attribute so that each component runs in its own process or so that some components share a process while others do not. You can also set android:process so that components of different applications run in the same process—provided that the applications share the same Linux user ID and are signed with the same certificates.
     The <application> element also supports an android:process attribute, to set a default value that applies to all components.
Android might decide to shut down a process at some point, when memory is low and required by other processes that are more immediately serving the user. Application components running in the process that\'s killed are consequently destroyed. A process is started again for those components when there\'s again work for them to do.
    When deciding which processes to kill, the Android system weighs their relative importance to the user. For example, it more readily shuts down a process hosting activities that are no longer visible on screen, compared to a process hosting visible activities. The decision whether to terminate a process, therefore, depends on the state of the components running in that process. The rules used to decide which processes to terminate is discussed below.
    默认下,同一个程序的所有组件都运行在同一个进程中并且大多数程序不必改变这一状况.然而,如果你非要与众不同,也可以通过修改manifest文件实现.
    manifest文件中的所有支持android:process属性的那些项(<activity>,<service>, <receiver>, 和<provider>)都可以指定一个进程,于是这些组件就会在这个进程中运行.你可以设置这个属性使每个组件运行于其自己的进程或只是其中一些组件共享一个进程.你也可以设置android:process以使不同应用的组件们可以运行于同一个进程—假如这些应用共享同一个用户ID并且有相同的数字证书.
    <application>元素也支持android:process属性,用于为所有的组件指定一个默认值.   Android可能在某些时刻决定关闭一个进程,比如内存很少了并且另一个进程更迫切的需要启动时.进程被关闭时,其中的组件们都被销毁.如果重新需要这些组件工作时,进程又会被创建出来.   当决定关闭哪些线程时,Android系统会衡量进程们与用户的紧密程度.例如,比起一个具有可见的activity的进程,那些所含activity全部不可见的进程更容易被关闭.如何决定一个进程是否被关闭,取决于进程中运行的组件们的状态.决定关闭进程的规则将在下面讨论.

    The Android system tries to maintain an application process for as long as possible, but eventually needs to remove old processes to reclaim memory for new or more important processes. To determine which processes to keep and which to kill, the system places each process into an "importance hierarchy" based on the components running in the process and the state of those components. Processes with the lowest importance are eliminated first, then those with the next lowest importance, and so on, as necessary to recover system resources.

    There are five levels in the importance hierarchy. The following list presents the different types of processes in order of importance (the first process is most important and is killed last):

    1.Foreground process A process that is required for what the user is currently doing. A process is considered to be in the foreground if any of the following conditions are true:
       It hosts an Activity that the user is interacting with (the Activity\'s onResume() method has been called).
       It hosts a Service that\'s bound to the activity that the user is interacting with.
       It hosts a Service that\'s running "in the foreground"—the service has called startForeground().
       It hosts a Service that\'s executing one of its lifecycle callbacks (onCreate(), onStart(), or onDestroy()).
       It hosts a BroadcastReceiver that\'s executing its onReceive() method.

    Generally, only a few foreground processes exist at any given time. They are killed only as a last resort—if memory is so low that they cannot all continue to run. Generally, at that point, the device has reached a memory paging state, so killing some foreground processes is required to keep the user interface responsive.

    2.Visible process A process that doesn\'t have any foreground components, but still can affect what the user sees on screen. A process is considered to be visible if either of the following conditions are true:
       It hosts an Activity that is not in the foreground, but is still visible to the user (its onPause() method has been called). This might occur, for example, if the foreground activity started a dialog, which allows the previous activity to be seen behind it.
       It hosts a Service that\'s bound to a visible (or foreground) activity.

    A visible process is considered extremely important and will not be killed unless doing so is required to keep all foreground processes running.

    3.Service process A process that is running a service that has been started with the startService() method and does not fall into either of the two higher categories. Although service processes are not directly tied to anything the user sees, they are generally doing things that the user cares about (such as playing music in the background or downloading data on the network), so the system keeps them running unless there\'s not enough memory to retain them along with all foreground and visible processes.

    4.Background process A process holding an activity that\'s not currently visible to the user (the activity\'s onStop() method has been called). These processes have no direct impact on the user experience, and the system can kill them at any time to reclaim memory for a foreground, visible, or service process. Usually there are many background processes running, so they are kept in an LRU (least recently used) list to ensure that the process with the activity that was most recently seen by the user is the last to be killed. If an activity implements its lifecycle methods correctly, and saves its current state, killing its process will not have a visible effect on the user experience, because when the user navigates back to the activity, the activity restores all of its visible state. See the Activities document for information about saving and restoring state.

    5.Empty process A process that doesn\'t hold any active application components. The only reason to keep this kind of process alive is for caching purposes, to improve startup time the next time a component needs to run in it. The system often kills these processes in order to balance overall system resources between process caches and the underlying kernel caches.

Android系统会尽量维持一个进程的生命,直到最终需要为新的更重要的进程腾出内存空间。为了决定哪个该杀哪个该留,系统会跟据运行于进程内的组件的和组件的状态把进程置于不同的重要性等级。当需要系统资源时,重要性等级越低的先被淘汰。   重要性等级被分为5个档。下面列出了不同类型的进程的重要性等级(第一个进程类型是最重要的,也是最后才会被杀的):
    1前台进程
用户当前正在做的事情需要这个进程。如果满足下面的条件,一个进程就被认为是前台进程:   这个进程拥有一个正在与用户交互的Activity(这个Activity的onResume() 方法被调用)。   这个进程拥有一个绑定到正在与用户交互的activity上的Service。   这个进程拥有一个前台运行的Service — service调用了方法 startForeground(). 这个进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(), 或onDestroy())的Service。   这个进程拥有正在执行其onReceive()方法的BroadcastReceiver。
通常,在任何时间点,只有很少的前台进程存在。它们只有在达到无法调合的矛盾时才会被杀--如果内存太小而不能继续运行时。通常,到了这时,设备就达到了一个内存分页调度状态,所以需要杀一些前台进程来保证用户界面的反应
    2可见进程
一个进程不拥有运行于前台的组件,但是依然能影响用户所见。满足下列条件时,进程即为可见:
这个进程拥有一个不在前台但仍可见的Activity(它的onPause()方法被调用)。当一个前台activity启动一个对话框时,就出了这种情况。
    3服务进程
一个可见进程被认为是极其重要的。并且,除非只有杀掉它才可以保证所有前台进程的运行,否则是不能动它的。   这个进程拥有一个绑定到可见activity的Service。   一个进程不在上述两种之内,但它运行着一个被startService()所启动的service。  尽管一个服务进程不直接影响用户所见,但是它们通常做一些用户关心的事情(比如播放音乐或下载数据),所以系统不到前台进程和可见进程活不下去时不会杀它。
    4后台进程
一个进程拥有一个当前不可见的activity(activity的onStop()方法被调用)。   这样的进程们不会直接影响到用户体验,所以系统可以在任意时刻杀了它们从而为前台、可见、以及服务进程们提供存储空间。通常有很多后台进程在运行。它们被保存在一个LRU(最近最少使用)列表中来确保拥有最近刚被看到的activity的进程最后被杀。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,那么杀死它的进程将不会对用户的可视化体验造成影响。因为当用户返回到这个activity时,这个activity会恢复它所有的可见状态。
    5空进程
一个进程不拥有入何active组件。   保留这类进程的唯一理由是高速缓存,这样可以提高下一次一个组件要运行它时的启动速度。系统经常为了平衡在进程高速缓存和底层的内核高速缓存之间的整体系统资源而杀死它们。  

    Android ranks a process at the highest level it can, based upon the importance of the components currently active in the process. For example, if a process hosts a service and a visible activity, the process is ranked as a visible process, not a service process.
    In addition, a process\'s ranking might be increased because other processes are dependent on it—a process that is serving another process can never be ranked lower than the process it is serving. For example, if a content provider in process A is serving a client in process B, or if a service in process A is bound to a component in process B, process A is always considered at least as important as process B.
    Because a process running a service is ranked higher than a process with background activities, an activity that initiates a long-running operation might do well to start a service for that operation, rather than simply create a worker thread—particularly if the operation will likely outlast the activity. For example, an activity that\'s uploading a picture to a web site should start a service to perform the upload so that the upload can continue in the background even if the user leaves the activity. Using a service guarantees that the operation will have at least "service process" priority, regardless of what happens to the activity. This is the same reason that broadcast receivers should employ services rather than simply put time-consuming operations in a thread.

    根据进程中当前活动的组件的重要性,Android会把进程按排在其可能的最高级别。例如,如果一个进程拥有一个service和一个可见的activity,进程会被定为可见进程,而不是服务进程。
    另外,如果被其它进程所依赖,一个进程的级别可能会被提高——一个服务于其它进程的进程,其级别不可能比被服务进程低。
    因为拥有一个service的进程比拥有一个后台activities的进程级别高,所以当一个activity启动一个需长时间执行的操作时,最好是启动一个服务,而不是简单的创建一个工作线程。尤其是当这个操作可能比activity的生命还要长时。例如,一个向网站上传图片的activity,应该启动一个service,从而使上传操作可以在用户离开这个activity时继续在后台执行。使用一个service保证了这个操作至少是在"服务进程"级别,而不用管activity是否发生了什么不幸。这同样是广播接收者应该使用service而不是简单地使用一个线程的理由。

再补充一下Android的进程模型Android的进程,线程模型

   在安装Android应用程序的时候,Android会为每个程序分配一个Linux用户ID,并设置相应的权限,这样其它应用程序就不能访问此应用程序所拥有的数据和资源了。
在Linux中,一个用户ID识别一个给定用户;在 Android 上,一个用户ID识别一个应用程序。应用程序在安装时被分配用户 ID,应用程序在设备上的存续期间内,用户ID保持不变。默认情况下,每个apk运行在它自己的Linux进程中。当需要执行应用程序中的代码时,Android会启动一个jvm,即一个新的进程来执行,因此不同的apk运行在相互隔离的环境中。

   下图显示了:两个 Android 应用程序,各自在其自己的基本沙箱或进程上。他们是不同的Linux user ID。
    image

   开发者也可以给两个应用程序分配相同的linux用户id,这样他们就能访问对方所拥有的资源.为了保留系统资源,拥有相同用户id的应用程序可以运行在同一个进程中,共享同一个jvm。如下图,显示了两个 Android 应用程序,运行在同一进程上。
不同的应用程序可以运行在相同的进程中。要实现这个功能,首先必须使用相同的私钥签署这些应用程序,然后必须使用 manifest 文件给它们分配相同的Linux用户ID,这通过用相同的值/名定义 manifest 属性 android:sharedUserId 来做到。

    image

Android进程知识的补充:

   下图是标准的Android 架构图,
   其中我们可以看到在“Android本地库 & Java运行环境层”中,Android 运行时中,
   Dalvik是Android中的java虚拟机,可支持同时运行多个虚拟机实例;每个Android应用程序都在自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例;    所有java类经过java编译器编译,然后通过SDK中的dx工具转成.dex格式交由虚拟机执行。

    image

    下一篇整理Android的线程部分。

分类:

技术点:

相关文章:

  • 2022-01-15
  • 2021-11-29
  • 2021-07-01
  • 2022-01-01
  • 2021-08-09
  • 2021-10-26
  • 2022-12-23
  • 2021-08-14
猜你喜欢
  • 2021-11-23
  • 2021-11-29
  • 2022-02-07
  • 2021-07-27
  • 2021-08-04
  • 2021-05-20
相关资源
相似解决方案