low memory killer

1 android 作为移动设备的操作系统,可能出现管理的内部不足的情况,为了尽量保证程序继续运行,需要有机制处理相关的内存问题。

2 Android 操作系统是基于linux的,linux 系统具有缓存内存的功能,即为了加快下次的速度,打开文件后放到内存中,再关闭后不会自动释放掉该内存,所以是cache memory。 

会出现linux设备内存有多大,linux系统就会尽量多占用内存,减少下次启动的时间。再内存不够用的时候才会去释放。

Android 设备延用了linux的这个机制,但做了部分的优化,不是缓存文件等,而是缓存进程,但打开一个app后,会创建该app的进程,退出app时不会立刻关掉该进程,所以该进程会占用部分内存。这样的优点是加快下次打开apk的速度。

3  Linux 有oom的机制,在内存不足时释放以让当前程序跑下去。android 同样也有oom处理机制(low memory killer).

4 内存不足时,杀掉谁腾出内存空间是有定义一个rule, 正常理解肯定是先杀手无用的且占内存较大的进程,保证前台显示的进程正常使用。

如driver中有一个数组,

如下,当内存少爷16 * 1024 (64m)时会杀手adj > 12的进程。

kernel 4.12 之前lmk 在内核中

drivers/staging/android/lowmemorykiller.c

static u32 lowmem_debug_level = 1;
static short lowmem_adj[6] = {
    0,
    1,
    6,
    12,
};

static int lowmem_adj_size = 4;
static int lowmem_minfree[6] = {
    3 * 512,    /* 6MB */
    2 * 1024,   /* 8MB */
    4 * 1024,   /* 16MB */
    16 * 1024,  /* 64MB */
};

5  kernel 4.12之后lmk 已经在内核中删除,使用用户空间的lmkd 执行该功能。

https://source.android.com/devices/tech/perf/lmkd

Historically, Android monitored system memory pressure using an in-kernel low memory killer (LMK) driver, a rigid mechanism that depends on hard-coded values. As of kernel 4.12, the LMK driver is removed from the upstream kernel and the userspace lmkd performs memory monitoring and process killing tasks.

用户空间的lmkd的code路径

system/memory/lmkd/

https://source.android.com/devices/tech/perf/lmkd

6  android 定义了adj,lmkd就是根据这个adj值去判断杀手哪个进程, adj就是rule的体现。

如下面重要的process,有些adj值比较小,lmkd 一般不会杀掉,大的值lmkd就会有被杀手的风险。

/proc/1/oom_score_adj   值为-1000    --- NATIVE_ADJ

/proc/2/oom_score_adj   值为0    --- FOREGROUND_APP_ADJ

/proc/1571/oom_score_adj  值为-800  ---PERSISTENT_PROC_ADJ

/proc/1711/oom_score_adj 值为200   --- PERCEPTIBLE_APP_ADJ

/proc/4283/oom_score_adj  值为100   -- VISIBLE_APP_ADJ

/proc/1608/oom_score_adj 值为600    --- HOME_APP_ADJ

/proc/2846/oom_score_adj  值为700    -- PREVIOUS_APP_ADJ

/proc/5155/oom_score_adj  值为900   --- CACHED_APP_MIN_ADJ

这边定义得adj值

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

UNKNOWN_ADJ1001Undetermined adj, usually the process to be cached
CACHED_APP_MAX_ADJ999Maximum adj for invisible processes
CACHED_APP_MIN_ADJ900Adj minimum for invisible processes
SERVICE_B_ADJ800Compared with a list, the service in B list has a smaller adhesion to users
PREVIOUS_APP_ADJ700User’s previous interaction process
HOME_APP_ADJ600Launcher process
SERVICE_ADJ500Application service process
HEAVY_WEIGHT_APP_ADJ400Heavyweight processes in the background
BACKUP_APP_ADJ300Processes that host backup related operations
PERCEPTIBLE_APP_ADJ200Perceptible processes, such as background music playback
VISIBLE_APP_ADJ100Activity process visible in the foreground
FOREGROUND_APP_ADJ0The process currently running in the foreground, that is, the program the user is interacting with
PERSISTENT_SERVICE_ADJ-700Process bound to system process or persistent process
PERSISTENT_PROC_ADJ-800The process of the persistent property, such as telephone
SYSTEM_ADJ-900System process
NATIVE_ADJ-1000Native process, not managed by the system

7   android 提供方法,方便apk 和 bin档调整优先级,针对重要的apk或进程防止被lmk给杀掉。

android 如何设置adj

系统同时也会动态设置apk 的adj值,当打开一个apk,前台时 adj为FOREGROUND_APP_ADJ,  退出到后台adj就变成了PREVIOUS_APP_ADJ。

Android AMS的OomAdjuster 就是专门处理这个事情,有对四大组件activity/service/broadcast receiver/content provider分别根据不同的情况设置相应的adj值。

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.md

这边给了OOM调节的设计原理及主要功能

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

逻辑较多

    private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

。。。。
        // important to least, and assign an appropriate OOM adjustment.
        int adj;
        int schedGroup;
        int procState;
        int cachedAdjSeq;
        int capability = 0;

        boolean foregroundActivities = false;
        boolean hasVisibleActivities = false;
        if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
。。。
        } else if (state.isRunningRemoteAnimation()) {
。。。
        } else if (app.getActiveInstrumentation() != null) {
。。。
        } else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
。。。
        } else if (psr.numberOfExecutingServices() > 0) {

。。。
        } else if (app == topApp) {
。。。
        } else {
。。。
        }

。。。
        // Examine all activities if not already foreground.
        if (!foregroundActivities && state.getCachedHasActivities()) {
。。。
            schedGroup = state.getCachedSchedGroup();
        }

        if (procState > PROCESS_STATE_CACHED_RECENT && state.getCachedHasRecentTasks()) {
。。。
        }

        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > PROCESS_STATE_FOREGROUND_SERVICE) {
            if (psr.hasForegroundServices()) {
。。。
            } else if (state.hasOverlayUi()) {
。。。
            }
        }
        // If the app was recently in the foreground and moved to a foreground service status,
        // allow it to get a higher rank in memory for some time, compared to other foreground
        // services so that it can finish performing any persistence/processing of in-memory state.
        if (psr.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
                && (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now
                || state.getSetProcState() <= PROCESS_STATE_TOP)) {
。。。
        }

        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
。。。
        }

        if (state.getCachedIsHeavyWeight()) {
。。。
        }

        if (state.getCachedIsHomeProcess()) {

。。。
        }

        if (state.getCachedIsPreviousProcess() && state.getCachedHasActivities()) {
。。。
        }
。。。
        for (int is = psr.numberOfRunningServices() - 1;
                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                        || procState > PROCESS_STATE_TOP);
                is--) {
            ServiceRecord s = psr.getRunningServiceAt(is);
            if (s.startRequested) {
。。。
            }

。。。
        }

        final ProcessProviderRecord ppr = app.mProviders;
        for (int provi = ppr.numberOfProviders() - 1;
                provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                        || procState > PROCESS_STATE_TOP);
                provi--) {
            ContentProviderRecord cpr = ppr.getProviderAt(provi);
            for (int i = cpr.connections.size() - 1;
                    i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                            || procState > PROCESS_STATE_TOP);
                    i--) {
。。。
            }
。。。
        }
。。。


            if (s.isForeground) {

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sure, here is an example of how to define a DDPG (Deep Deterministic Policy Gradient) class in Python: ``` import tensorflow as tf import numpy as np class DDPG: def __init__(self, state_size, action_size, lower_bound, upper_bound): self.memory = [] self.batch_size = 64 self.gamma = 0.99 self.tau = 0.001 self.sess = tf.Session() tf.keras.backend.set_session(self.sess) self.actor = self.create_actor_model(state_size, upper_bound) self.critic = self.create_critic_model(state_size, action_size) self.target_actor = self.create_actor_model(state_size, upper_bound) self.target_critic = self.create_critic_model(state_size, action_size) self.target_actor.set_weights(self.actor.get_weights()) self.target_critic.set_weights(self.critic.get_weights()) self.critic.compile(optimizer=tf.keras.optimizers.Adam(0.001), loss='mse') def create_actor_model(self, state_size, upper_bound): input_layer = tf.keras.layers.Input(shape=(state_size,)) x = tf.keras.layers.Dense(256, activation='relu')(input_layer) x = tf.keras.layers.Dense(256, activation='relu')(x) output_layer = tf.keras.layers.Dense(1, activation='tanh')(x) output_layer = tf.keras.layers.Lambda(lambda x: x * upper_bound)(output_layer) model = tf.keras.models.Model(inputs=input_layer, outputs=output_layer) return model def create_critic_model(self, state_size, action_size): state_input_layer = tf.keras.layers.Input(shape=(state_size,)) state_x = tf.keras.layers.Dense(16, activation='relu')(state_input_layer) state_x = tf.keras.layers.Dense(32, activation='relu')(state_x) action_input_layer = tf.keras.layers.Input(shape=(action_size,)) action_x = tf.keras.layers.Dense(32, activation='relu')(action_input_layer) merged_layer = tf.keras.layers.concatenate([state_x, action_x]) merged_layer = tf.keras.layers.Dense(256, activation='relu')(merged_layer) output_layer = tf.keras.layers.Dense(1)(merged_layer) model = tf.keras.models.Model(inputs=[state_input_layer, action_input_layer], outputs=output_layer) return model def update_target_networks(self): actor_weights = np.array(self.actor.get_weights()) target_actor_weights = np.array(self.target_actor.get_weights()) critic_weights = np.array(self.critic.get_weights()) target_critic_weights = np.array(self.target_critic.get_weights()) self.target_actor.set_weights(self.tau * actor_weights + (1 - self.tau) * target_actor_weights) self.target_critic.set_weights(self.tau * critic_weights + (1 - self.tau) * target_critic_weights) def get_action(self, state): return self.actor.predict(state) def remember(self, state, action, reward, next_state, done): self.memory.append([state, action, reward, next_state, done]) def train(self): if len(self.memory) < self.batch_size: return samples = np.array(random.sample(self.memory, self.batch_size)) states = np.vstack(samples[:, 0]) actions = np.array(samples[:, 1]) rewards = np.array(samples[:, 2]) next_states = np.vstack(samples[:, 3]) done = np.vstack(samples[:, 4]) target_actions = self.target_actor.predict(next_states) target_q_values = self.target_critic.predict([next_states, target_actions]) y = rewards + self.gamma * target_q_values * (1 - done) self.critic.train_on_batch([states, actions], y) with tf.GradientTape() as tape: predicted_actions = self.actor(states) actor_loss = -tf.math.reduce_mean(self.critic([states, predicted_actions])) actor_gradients = tape.gradient(actor_loss, self.actor.trainable_variables) self.sess.run(self.actor.optimizer.apply_gradients(zip(actor_gradients, self.actor.trainable_variables))) self.update_target_networks() def save_model(self, name): self.actor.save_weights(name + '_actor.h5') self.critic.save_weights(name + '_critic.h5') def load_model(self, name): self.actor.load_weights(name + '_actor.h5') self.critic.load_weights(name + '_critic.h5') self.target_actor.set_weights(self.actor.get_weights()) self.target_critic.set_weights(self.critic.get_weights()) ``` This is just an example and can be customized depending on the specific use case.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值