Estou tentando definir o oom_adj
valor para o eliminador de falta de memória e, cada vez que faço isso (independentemente do processo), recebo exatamente um a menos do que defini (pelo menos para números inteiros positivos. Não tentei números inteiros negativos desde que eu deseja que esses processos sejam eliminados primeiro pelo OOM Killer).
[root@server ~]# echo 10 > /proc/12581/oom_adj
[root@server ~]# cat /proc/12581/oom_adj
9
[root@server ~]# echo 9 > /proc/12581/oom_adj
[root@server ~]# cat /proc/12581/oom_adj
8
[root@server ~]# echo 8 > /proc/12581/oom_adj
[root@server ~]# cat /proc/12581/oom_adj
7
[root@server ~]# echo 7 > /proc/12581/oom_adj
[root@server ~]# cat /proc/12581/oom_adj
6
[root@server ~]#
Esse é o comportamento esperado? Se não, por que isso está acontecendo?
Responder1
oom_adj
está obsoleto e é fornecido apenas para fins legados. Internamente o Linux usa oom_score_adj
o que tem um alcance maior: oom_adj
vai até 15 enquanto oom_score_adj
vai até 1000.
Sempre que você escreve para oom_adj
(digamos 9), o kernel faz isso:
oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
e armazena isso em oom_score_adj
. OOM_SCORE_ADJ_MAX
é 1000 e OOM_DISABLE
é -17.
Então, para 9 você obterá oom_adj=(9 * 1000) / 17 ~= 529.411
e, como esses valores são inteiros, oom_score_adj
conterá 529.
Agora, quando você ler oom_adj
o kernel, fará isso:
oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
Então, para 529 você obterá: oom_adj = (529 * 17) / 1000 = 8.993
e como o kernel usa números inteiros e aritmética de números inteiros, isso se tornará 8.
Então aí... você escreve 9 e obtém 8 por causa da aritmética de ponto fixo/inteiro.