进程管理&内存管理
- 进程
生命周期
进程优先级:- 前台进程
- 可见进程
- 服务进程
- 后台进程 (LRU Cache & 占用内存大小)
onTrimMemory
- GC
Dalvik | ART 的进程级行为(一个进程就是一个虚拟机实例),一个进程占用内存达到system定义阀值系统抛OOM异常。
dalvik.vm.heapgrowthlimit
dalvik.vm.heapsize
GC原因:
Concurrent
不会暂停应用线程的并发垃圾回收。此垃圾回收在后台线程中运行,而且不会阻止分配。
Alloc
您的应用在堆已满时尝试分配内存引起的垃圾回收。在这种情况下,分配线程中发生了垃圾回收。
Explicit
由应用明确请求的垃圾回收,例如,通过调用 gc ( )
NativeAlloc
原生分配(如位图或 RenderScript 分配对象)导致出现原生内存压力,进而引起的回收。
频繁GC导致线程pause,短时间内创建大量对象容易引起频繁GC,造成内存抖动现象,可明显感知卡顿。
内存占用高:
- 达到进程上线无法alloct,抛OOM(进程级)
- 导致系统杀后台进程(系统级)
- GC(进程级)
AppOps
AppOpsManager.java
checkOp(int op, int uid, String packageName)
OP_GET_USAGE_STATS
/**
* API for interacting with "application operation" tracking.
*
* <p>This API is not generally intended for third party application developers; most
* features are only available to system applications. Obtain an instance of it through
* {@link Context#getSystemService(String) Context.getSystemService} with
* {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p>
*/
AppOps是Android 自API19加入的应用权限授权管理框架,虽然到了后来6.0引入了另外一套方案Android Runtime Permission,但是 AppOps并没有被废弃掉,它依然存在于系统框架内,只不过没有图形管理入口而已,但是依然保留并增加了API,而且AppOps命令行管理工具依然可用。
“adb shell cmd appops”
usage: appops set [--user <USER_ID>] <PACKAGE> <OP> <MODE>
appops get [--user <USER_ID>] <PACKAGE> [<OP>]
appops reset [--user <USER_ID>] [<PACKAGE>]
<PACKAGE> 指定的应用包名
<OP> 指定一项 AppOps 操作权限.
<USER_ID> 指定系统用户ID(5.0引入的多用户),如果未指定则默认当前登录用户(可选)
specified, the current user is assumed.
<allow|ignore|deny|default> allow 放行权限,ignore表示拒绝权限,但是应用不知道自己的权限被拒绝(这个选项用来对付国内流氓权限),deny明确拒绝权限,并告知应用权限申请被拒绝,default恢复默认的设置
OP即权限
api24新增 RUN_IN_BACKGROUND : 后台运行服务权限,禁用后系统将在应用进入后台几分钟后将后台服务杀死 commit
BroadCast
静态注册会唤起进程,如果遇到隐式广播大量进程被唤起。有序广播更麻烦。
影响process state,onReceive执行在main thread,ANR风险,而且后台ANR不会弹窗提示。return之后process state provity降低,等待kill。onReceive中开启异步线程或者 starting background services都不能阻止被杀的可能性。如果确实需要收到广播后做long time work推荐JobScheduler
针对broadcast可能导致的问题系统做了哪些
- Apps targeting Android 7.0 (API level 24) and higher do not receive CONNECTIVITY_ACTION broadcasts if they declare their broadcast receiver in the manifest. Apps will still receive CONNECTIVITY_ACTIONbroadcasts if they register their BroadcastReceiver with Context.registerReceiver() and that context is still valid.
- Apps cannot send or receive ACTION_NEW_PICTURE or ACTION_NEW_VIDEO broadcasts. This optimization affects all apps, not only those targeting Android 7.0 (API level 24).
- Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers. If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically). 除了这些例外
WakeLock&Wakeup(耗电)
PowerManager.WakeLock
The following wake lock levels are defined, with varying effects on system power. These levels are mutually exclusive - you may only specify one of them.
Flag Value | CPU | Screen | Keyboard |
---|---|---|---|
PARTIAL_WAKE_LOCK | On* | Off | Off |
SCREEN_DIM_WAKE_LOCK | On | Dim | Off |
SCREEN_BRIGHT_WAKE_LOCK | On | Bright | Off |
FULL_WAKE_LOCK | On | Bright | Bright |
*If you hold a partial wake lock, the CPU will continue to run, regardless of any display timeouts or the state of the screen and even after the user presses the power button. In all other wake locks, the CPU will run, but the user can still put the device to sleep using the power button.
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();
..screen will stay on during this section..
wl.release();
adb shell dumpsys power 可以查看wakelock持有情况
AlarmManager
When a wakeup alarm is triggered, the device comes out of low-power mode and holds a partial wake lock while executing the alarm's onReceive() or onAlarm() method. If wakeup alarms are triggered excessively, they can drain a device's battery.
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
60 * 1000, alarmIntent);
void set (int type,long triggerAtMillis,PendingIntent operation)
Parameters | |
---|---|
type |
int : type of alarm.Value is RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP or ELAPSED_REALTIME. |
triggerAtMillis |
long : time in milliseconds that the alarm should go off, using the appropriate clock (depending on the alarm type). |
operation |
PendingIntent : Action to perform when the alarm goes off; typically comes from IntentSender.getBroadcast(). |
CPU Usage
Doze & App Standby
译文
Doze打盹模式共有五种状态,不同状态间的切换如下图所示,如果厂家没有修改时间的话,因此从灭屏到Doze模式,至少需要61分钟,官方是60分钟,但需要1分钟作为运动监测。