Appp提高进程存活率
- 系统由于体验和性能的考虑,app在退到后台时系统不会kill掉这个进程,而是将其缓存起来。
- 打开应用越多,后台缓存的应用也越多。
- 在系统内存不足的情况下,系统开始依据自身的一套进程进程回收机制来判断要kill哪些进程,来释放内存供前台应用使用。杀进程回收内存的机制叫做 Low Memory Killer
我们所要做的就是尝试把处于后台的低优先级应用,提升到高优先级甚至关键优先级。
我们要了解一下内存阈值这个概念:当进程所使用的内存超过这个值的时候系统会抛出oom杀掉该进程,只是表示进程使用内存超过了限制而不是说现在内存不足了。每个手机有各自的不同的内存阈值。内存阈值可以通过adb shell 命令查看
真机必须是root的才可以查看。
adb shell cat /sys/module/lowmemorykiller/parameters/minfree
一般会有6个输出值(单位为4KB)
输出的数值依次为:
- 前台进程阈值
- 可见进程阈值
- 服务进程阈值
- 后台进程阈值
- contendProvider阈值
- 空进程阈值
adj级别 | 值 | 解释 |
---|---|---|
UNKNOWN_ADJ | 16 | 预留的最低级别,一般对于缓存的进程才有可能设置成这个级别 |
CACHED_APP_MAX_ADJ | 15 | 缓存进程,空进程,在内存不足的情况下就会优先被kill |
CACHED_APP_MIN_ADJ | 9 | 缓存进程,也就是空进程 |
SERVICE_B_ADJ | 8 | 不活跃的进程 |
PREVIOUS_APP_ADJ | 7 | 切 |
HOME_APP_ADJ | 6 | 与Home交互的进程 |
SERVICE_ADJ | 5 | 有Service的进程 |
HEAVY_WEIGHT_APP_ADJ | 4 | 高权重进程 |
BACKUP_APP_ADJ | 3 | 正在备份的进程 |
PERCEPTIBLE_APP_ADJ | 2 | 可感知的进程,比如那种播放音乐 |
VISIBLE_APP_ADJ | 1 | 可见进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
PERSISTENT_SERVICE_ADJ | -11 | 重要进程 |
PERSISTENT_PROC_ADJ | -12 | 核心进程 |
SYSTEM_ADJ | -16 | 系统进程 |
NATIVE_ADJ | -17 | 系统起的Native进程 |
adj值越高越容易被干掉 | ||
一般adj值超过3就容易被干掉 |
//
通过前台服务提高进程存活率
public class ForegroundService extends Service {
public static final int ID = 0x11;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public ForegroundService() {
}
private static final String TAG = "ForegroundService";
@Override
public void onCreate() {
Log.d(TAG, "onCreate: ");
super.onCreate();
createNotificationChannel(getApplicationContext());
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
Notification notification = builder.setSmallIcon(R.drawable.ic_launcher_foreground).build();
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
startForeground(ID, notification);
startService(new Intent(this, InnerService.class));
}
public static final String CHANNEL_ID = "ForeGround";
public void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "createNotificationChannel: ");
CharSequence name = "channel_name";
String description = "channel_description";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
private static class InnerService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private static final String TAG = "InnerService";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
//发送与KeepLiveService中ID相同的Notification,然后将其取消并取消自己的前台显示
Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID);
builder.setSmallIcon(R.drawable.ic_launcher_foreground);
startForeground(ID, builder.build());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: ");
stopForeground(true);
NotificationManagerCompat notificationManagerCompat = (NotificationManagerCompat) NotificationManagerCompat.from(getApplicationContext());
notificationManagerCompat.cancel(ID);
stopSelf();
}
}, 100);
}
}
}
adb shell cat /proc/6091/oom_adj
6091:为进程id,可以在AndroidStudio上查看
// 没有前台服务时,应用退到后台进程adj值为11,使用前台进程时,app退到后台adj值为3(huaWei Nova4真机亲测)。