zoukankan      html  css  js  c++  java
  • 提高app进程存活率

    Appp提高进程存活率

    • 系统由于体验和性能的考虑,app在退到后台时系统不会kill掉这个进程,而是将其缓存起来。
    • 打开应用越多,后台缓存的应用也越多。
    • 在系统内存不足的情况下,系统开始依据自身的一套进程进程回收机制来判断要kill哪些进程,来释放内存供前台应用使用。杀进程回收内存的机制叫做 Low Memory Killer
      avatar

    我们所要做的就是尝试把处于后台的低优先级应用,提升到高优先级甚至关键优先级。
    我们要了解一下内存阈值这个概念:当进程所使用的内存超过这个值的时候系统会抛出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真机亲测)。

  • 相关阅读:
    如何掌握所有的程序语言
    Excel技巧:如何绘制一份优秀的甘特图(项目管理)
    Excel技巧:如何绘制一份优秀的甘特图(项目管理)
    程序员的鄙视链
    程序员的鄙视链
    程序员的鄙视链
    程序员之间的鄙视链
    炮(棋盘DP)
    最长公共子上升序列
    black hack
  • 原文地址:https://www.cnblogs.com/FCY-LearningNotes/p/14050789.html
Copyright © 2011-2022 走看看