Android的进程、线程与优先级
来源:互联网 发布:js代码获取ip地址 编辑:程序博客网 时间:2024/04/28 06:41
一、结论
1、Android中进程的优先级与垃圾回收机制相关,优先级越低被垃圾回收的机会越大。当内存不足的时候,总是低优先级的进程被最先回收;
2、Android中线程的优先级与调用顺序有关,优先级越高被调用的可能性越高(注意,是可能性更高),也就是说即使线程A的优先级大于线程B,同等情况下线程A不一定先于线程B被调用。
二、进程与线程
1、什么是进程、线程
如果你想要一个程序运行得快,那么可以将其断开为多个片段,在单独的处理器上运行每个片段,这是并发编程最主要的考虑,简单理解:
- 进程(process):是一块包含了某些资源的内存区域,是操作系统的最小可执行单元。操作系统利用进程把它的工作划分为一些功能单元。一个程序至少对应一个进程。
- 线程(thread):是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程至少对应一个线程。
在Android中,每个app运行时前首先创建一个进程,该进程是由Zygote fork出来的,用于承载App上运行的各种Activity/Service等组件。大多数情况一个App就运行在一个进程中,除非:
(1)配置Android:process属性:
a.进程名为com.goodong.com.process1:
<activity android:name=".MyFirstActivity" android:process="com.goodong.com.process1" > <intent-filter> …… </intent-filter> </activity>
b.配置进程名为”:process2”(包名+process2):
<activity android:name=".MyFirstActivity" android:process=":process2" > <intent-filter>…… </intent-filter> </activity>
注意:第2种命名进程的方式与第1中命名方式的区别在于,后者不能做到:让不同应用程序的组件运行在同一个进程中。
(2)通过native代码fork进程:
应用程序的进程是由Zygote创建的,在ActivityManagerService中的startProcessLocked中调用了Process.start()方法。并通过连接调用Zygote的native方法forkAndSpecialize,执行fork任务。
2、线程的调度
线程对应用来说非常常见,比如每次new Thread().start都会创建一个新的线程。该线程与App所在进程之间资源共享,从Linux角度来说进程与线程除了是否共享资源外,并没有本质的区别。
Java的线程机制是抢占式的,这表示调度机制会周期性地中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片,使得每个线程都会分配到数量合理的时间去执行它的任务。
CPU轮流为每个任务分配其占用时间。每个任务都觉得自己在一直占用CPU,但事实上CPU时间是划分成片段分配给了所有任务。使用线程机制是一种建立透明的、可扩展的程序的方法,如果程序运行太慢,为机器添加一个CPU就能很容易地加快程序的运行速度。
请注意,尽管多任务和多线程往往是使用多处理器系统的最合理方式,但多线程编程并不是仅仅针对多处理器,即使在单处理上,并发编程也是有用武之地的。这是因为,如果一个程序包含了多个顺序执行的任务(不是并发执行),因为每个任务都可能被阻塞,一旦任务被阻塞,程序就停止执行。但在并发编程下,多个任务并发执行,单任务阻塞并不会直接导致程序停止执行。
三、Android进程的优先级
1、优先级意味着什么
优先级的意思是:针对多个对象的某种操作的执行顺序。上面我们说过,进程是一块内存区域,因为对进程而言,优先级意味着何时释放资源:
- 在释放进程资源的时候,让优先级低的进程先释放释放资源;
- 如果即将被运行的进程的优先级比正在运行的进程的优先级高,则系统可以强行剥夺正在运行的进程的资源,让优先级高的进程先运行。
2、有多少个优先级
在Android 中,进程的优先级就是oom_adj的值,而oom_adj被定义在init.rc中:
· Define the memory thresholds at which the above process classes will· be killed. These numbers are in pages (4k). setprop ro.FOREGROUND_APP_ADJ 0 setprop ro.VISIBLE_APP_ADJ 1 setprop ro.SECONDARY_SERVER_ADJ 2 setprop ro.HIDDEN_APP_MIN_ADJ 7 setprop ro.CONTENT_PROVIDER_ADJ 14 setprop ro.EMPTY_APP_ADJ 15
名称 oom_adj 解释:
3、oom_adj值会随着进程的状态变化而变化
adb连接手机后,笔者从桌面上启动了知乎,用adb shell dumpsys activity查看activitys的分布,可以看到activity的次序如下:
这时候另开一个命令行窗口查看进程的进程号:
这个时候知乎有两个进程,分别是15345和15725,使用cat /proc//oom_adj 命令查看它们的oom_adj值:
它们的值分别是0和11(oom_adj值是可以修改);
将知乎退到后台再查询它们的oom_adj值:
两个进程的值分别是9和13(退后台前是0和11)。
4、如何根据oom_adj的值判断回收时机
init.rc中定义垃圾回收的阈值:
· Write value must be consistent with the above properties.· Note that the driver only supports 6 slots, so we have combined some of· the classes into the same memory level; the associated processes of higher· classes will still be killed first.·写入的值必须符合上面的属性。注意设备只支持6个等级,所以某些·类会被合并到同一个等级中。拥有更高等级的进程将被优先杀死。 setprop ro.FOREGROUND_APP_MEM 1536(6M) setprop ro.VISIBLE_APP_MEM 2048(8M) setprop ro.SECONDARY_SERVER_MEM 4096(16M) setprop ro.HIDDEN_APP_MEM 5120(20M) setprop ro.CONTENT_PROVIDER_MEM 5632(22M) setprop ro.EMPTY_APP_MEM 6144(24M)
这些数字也就是对应的内存阈值,一旦低于该值,Android便开始按顺序关闭相应的进程 。具体的回收实现在ActivityManagerService.java中的函数trimApplications():
- 首先移除package被移走的无用进程;
基于进程当前状态,更新oom_adj值,然后进行以下操作:
- 移除没有activity在运行的进程。如果APP已经保存了所有的activity状态,结束这个APP;
- 最后,如果目前还是有很多activities 在运行,那么移除那些activity状态已经保存好的activity。
当系统内存短缺时Android的Low Memory Killer根据需要杀死进程释放其内存,简单说就是寻找一个最合适的进程杀死,从而释放它占用的内存,最合适指的是:
- oom_adj越大
- 占用物理内存越多
四、Android线程的优先级
1、线程的简单示范
从CPU的角度看,Android线程就是Java线程。因而Android线程的优先级就是Java线程的优先级(但在Android开发中,笔者似乎从未操心过线程的优先级)。
Java中使用线程最常用的方法是:
- 实现Runnable接口,覆写run()方法;
继承Thread类,覆写run()方法(实际也是实现Runnable接口)。
先实现实现Runnable接口:public class RunabbleImp implements Runnable{ @Overridepublic void run() {doSomeThing();}private void doSomeThing() {System.out.println(Thread.currentThread().getName()+" is running!"); }}
测试一下:
public class ThreadTest { public static void main(String[] args) { RunabbleImp runabbleImp = new RunabbleImp(); runabbleImp.run(); Thread thread = new Thread(new RunabbleImp()); thread.start(); } }
打印结果:
main is running! Thread-0 is running!
可以看出runabbleImp.run();实际上是在主线程中运行,而thread.start();已经开启了一个新线程。
2、线程的优先级
线程的优先级将线程的重要性传递给调度器。尽管CPU处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先级高的线程先执行。然而,这并不意味着优先权低的线程将得不到执行(也就是说,优先级不会导致死锁)。优先级较低的线程仅仅是执行的频率较低。
可以用getPriority()获取当前线程的优先级,并且在任何时刻都可以通过setPriority()来修改它:
public class PriorityThread implements Runnable { private int timeCount = 5; private int priority; public PriorityThread(int priorityIn) { priority = priorityIn; }@Overridepublic String toString() { return Thread.currentThread() +":"+timeCount;}@Overridepublic void run() { Thread.currentThread().setPriority(priority); while(true){ for (int i = 0; i < 100000; i++) { double d = (Math.PI + Math.E)/(double)i; if(i % 1000 == 0){ Thread.yield(); } } System.out.println(this); if(--timeCount ==0){ break; } }}public class ThreadTest { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { exec.execute(new PriorityThread(Thread.MIN_PRIORITY + i)); } } exec.execute(new PriorityThread(Thread.MAX_PRIORITY)); exec.shutdown(); }
部分打印结果如下:
…… Thread[pool-1-thread-6,10,main]:1 …… Thread[pool-1-thread-5,5,main]:1 …… Thread[pool-1-thread-3,3,main]:1 Thread[pool-1-thread-1,1,main]:1 …… Thread[pool-1-thread-2,2,main]:1 Thread[pool-1-thread-4,4,main]:1
笔者执行多次后结果显示Thread[pool-1-thread-6,10,main]总是最先执行完毕,其他线程执行完毕顺序大致上是优先级高的先执行完毕,但是无法保证。
- Android的进程、线程与优先级
- android进程、线程的优先级
- Android的进程优先级与进程回收
- Android的进程优先级与进程回收
- Android的进程优先级与进程回收
- 进程与线程(三)进线程的优先级操作
- Android文档——进程优先级与线程
- android 进程的优先级
- Android的进程优先级
- android进程的优先级
- Android的进程优先级
- Android进程的优先级
- Android的进程优先级与进程回收详解
- android的进程与线程
- android的进程与线程
- Android的进程与线程
- Android的线程与进程
- Android的进程与线程
- Hadoop中MapReduce实现join多种实例分析
- C++必读书籍推荐
- 【python学习笔记】flask实现简单的接收json返回json的接口
- 怎样调试ui freeze
- ImageView加载图片的简单方法
- Android的进程、线程与优先级
- ES6中this值为null
- 【android】悬浮球
- spark创建hbase表(非分区表)
- 【读书笔记】《Effective Java》(1)--创建和销毁对象
- 毛超帅 开发那点事:服务器任务管理svchost.exe是否是病毒的判定和查找以及解决方案______软件开发-JAVA
- 简单选择排序
- TextView显示丰富多彩的文字(二)——如何使用ParagraphStyle格式化段落
- Android中的状态保存-SharedPreferences和Bundle(文末小彩蛋)