Как протестировать oom-уничтожителя из командной строки

Уничтожитель OOM или Из Уничтожителя Памяти является процессом, который использует ядро Linux, когда система является критически низкой на памяти.... Это максимизирует использование системной памяти путем обеспечения, что память, которая выделяется процессам, активно используется.

Этот вопрос, которому самоотвечают, спрашивает:

  • Как протестировать oom-уничтожителя из командной строки?

Был бы принят более быстрый метод, чем 1/2 час, который требуется в самоответе.

8
задан 11 November 2019 в 13:36

5 ответов

Ключ к инициированию уничтожителя OOM быстро должен постараться не увязать доступами к диску. Так:

  1. Стараются не подкачивать, если Ваша цель не состоит в том, чтобы конкретно протестировать поведение OOM, когда подкачка используется. можно отключить подкачку перед тестом, затем повторно включить его впоследствии. swapon -s говорит Вам, какие подкачки в настоящее время включаются. sudo swapoff -a отключает все подкачки; sudo swapon -a обычно достаточно, чтобы повторно включить им.

  2. Стараются не вкраплять доступы памяти доступами недиска подкачки. , Что находящийся в globbing метод в конечном счете израсходовал Вашу доступную память (учитывая достаточные записи в Вашей файловой системе), но причина требуется такую память, должен хранить информацию, что это получает путем доступа к файловой системе. Даже с SSD, вероятно, что так большая часть времени проведена, читая из диска, даже если подкачка выключена. Если Ваша цель состоит в том, чтобы конкретно протестировать поведение OOM на доступы памяти, которые вкраплены доступами к диску, тот метод разумен, возможно, даже идеален. Иначе можно достигнуть цели намного быстрее.

, После того как Вы отключили подкачку, любой метод, который редко читает из физического диска, должен быть довольно быстрым. Это включает tail /dev/zero (, нашел [1 124], falstaff, прокомментировал выше [1 126] Doug Smythies ). Хотя это читает из устройства посимвольного ввода-вывода /dev/zero, то "устройство" просто генерирует пустые байты (т.е. байты всех нулей) и не включает доступа физического диска, после того как узел устройства был открыт. Тот метод работает, потому что tail ищет запаздывающие строки в его входе, но поток нулей не содержит символа новой строки, таким образом, это никогда не заставляет строк отбрасывать.

, Если Вы поиск остроты на интерпретируемом языке , который выделяет и заполняет память алгоритмически, Вы находитесь в удаче. На примерно любом интерпретируемом языке общего назначения легко выделить большую память и записать в него, иначе не используя его. Вот острота Perl, которая, кажется, о с такой скоростью, как tail /dev/zero (хотя я не сравнил ее экстенсивно):

perl -wE 'my @xs; for (1..2**20) { push @xs, q{a} x 2**20 }; say scalar @xs;'

С подкачкой, выключенной на старой машине с 4 гибибайтами RAM, и это и tail /dev/zero заняло приблизительно десять секунд каждый раз, когда я выполнил их. Оба должны все еще хорошо работать на более новых машинах с намного большим количеством RAM, чем это. Можно сделать тот perl команда намного короче, если целью является краткость.

, Что острота Perl неоднократно генерирует (q{a} x 2**20) отдельные умеренно длинные строки - приблизительно миллион символов каждый - и сохраняет их всех вокруг путем хранения их в массиве (@xs). Можно скорректировать числа для тестирования. Если Вы не используете всю доступную память, острота производит общее количество созданных строк. Принятие уничтожителя OOM действительно уничтожает perl - с точной командой, показанной выше и никакие квоты ресурса, чтобы помешать, я верю на практике, что это всегда будет - затем, Ваша оболочка должна показать Вам Killed. Затем как в любой ситуации OOM, dmesg имеет детали.

, Хотя мне нравится этот метод, он действительно иллюстрирует что-то полезное о записи, компиляции и использовании программы C - как та в [1 128] ответ Doug Smythies . Выделение памяти и доступ к памяти не чувствуют себя подобно отдельным вещам на высокоуровневых интерпретируемых языках, но в C можно заметить и, если Вы выбираете, исследуете те детали.

<час>

Наконец, необходимо всегда проверять, что уничтожитель OOM на самом деле, что уничтожило программу . Один способ проверить состоит в том, чтобы осмотреть dmesg. Вопреки широко распространенному мнению это на самом деле возможно для попытки выделить память для сбоя быстро, даже на Linux. Легко заставить это произойти с огромными выделениями, которые, очевидно, перестанут работать..., но даже они могут неожиданно произойти. И на вид разумные выделения могут перестать работать быстро. Например, на моей тестовой машине, perl -wE 'say length q{a} x 3_100_000_000;' успешно выполняется, и perl -wE 'say length q{a} x 3_200_000_000;' печать:

Out of memory!
panic: fold_constants JMPENV_PUSH returned 2 at -e line 1.

Ни один не инициировал уничтожителя OOM. Разговор в более общем плане:

  • , Если Ваша программа предварительно вычисляет, сколько памяти необходимо и просит ее в единственном выделении, выделение может успешно выполниться (и если она делает, уничтожитель OOM может или не может закрыть программу, когда достаточно памяти используется), или выделение может просто перестать работать.
  • Расширение массива к огромной длине путем добавления многих, много элементов к нему часто инициировали уничтожителя OOM в фактической практике, но заставляя это сделать это надежно в тестировании удивительно хитро. Путем это почти всегда делается - потому что это - самый эффективный способ сделать это - должен сделать каждый новый буфер со способностью x времена мощность старого буфера. Общие ценности для [1 132] x включают 1.5 и 2 (и технику часто называют "удвоением таблицы"). Это иногда устраняет разрыв между тем, сколько памяти может на самом деле выделяться и использоваться и сколько знает ядро, слишком много, чтобы даже потрудиться симулировать раздавать.
  • Выделения памяти могут перестать работать по причинам, которые имеют мало общего с ядром или сколько памяти на самом деле доступно, и это не инициировало уничтожителя OOM также. В частности, программа может перестать работать быстро на выделении любого размера после успешного выполнения очень большого количества крошечных выделений. Этот отказ происходит в бухгалтерии, которая выполняется самой программой - обычно через средство библиотеки как [1 119]. Я подозреваю, что это - то, что произошло со мной сегодня, когда, во время тестирования с [1 120] массивы (которые на самом деле реализованы как двунаправленные связанные списки), bash выход с сообщением об ошибке, говоря выделение из 9 байтов отказавший.

уничтожителя OOM намного легче инициировать случайно, чем инициировать намеренно.

В попытке сознательно инициировать уничтожителя OOM, один путь вокруг этих проблем состоит в том, чтобы запуститься путем запроса слишком большой памяти и постепенно идти меньший, как [1 129], программа Doug Smythies C делает. Иначе должен выделить целый набор умеренно размерных блоков памяти, которая является тем, что выше делает острота Perl, показанная: ни одна из millionish-символьных-строк (плюс немного дополнительного использования памяти негласно) не является особенно налоговой, но взятая вместе, все покупки на один мегабайт складывают.

7
ответ дан 23 November 2019 в 05:24

Этот ответ использует программу C для выделения как можно большей памяти, затем постепенно на самом деле использует ее, приводя к "Уничтоженному" от защиты OOM.

/*****************************************************************************
*
* bla.c 2019.11.11 Smythies
*       attempt to invoke OOM by asking for a rediculous amount of memory
*       see: https://askubuntu.com/questions/1188024/how-to-test-oom-killer-from-command-line
*       still do it slowly, in chunks, so it can be monitored.
*       However simplify the original testm.c, for this example.
*
* testm.cpp 2013.01.06 Smythies
*           added a couple more sleeps, in attempts to observe stuff on linux.
*
* testm.cpp 2010.12.14 Smythies
*           attempt to compile on Ubuntu Linux.
*
* testm.cpp 2009:03:18 Smythies
*           This is not the first edit, but I am just adding the history
*           header.
*           How much memory can this one program ask for and sucessfully get?
*           Done in two calls, to more accurately simulate the program I
*           and wondering about.
*           This edit is a simple change to print the total.
*           the sleep calls have changed (again) for MS C version 2008.
*           Now they are more like they used to be (getting annoying).
*                                                                     Smythies
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>

#define CR 13

int main(){
   char *fptr;
   long i, k;

   i = 50000000000L;

   do{
      if(( fptr = (char *)malloc(i)) == NULL){
         i = i - 1000;
      }
   }
   while (( fptr == NULL) && (i > 0));

   sleep(15);  /* for time to observe */
   for(k = 0; k < i; k++){   /* so that the memory really gets allocated and not just reserved */
      fptr[k] = (char) (k & 255);
   } /* endfor */
   sleep(60);  /* O.K. now you have 1 minute */
   free(fptr); /* clean up, if we get here */
   return(0);
}

результат:

doug@s15:~/c$ ./bla
Killed
doug@s15:~/c$ journalctl -xe | grep oom
Nov 11 16:08:24 s15 kernel: mysqld invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
Nov 11 16:08:25 s15 kernel:  oom_kill_process+0xeb/0x140
Nov 11 16:08:27 s15 kernel: [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
Nov 11 16:08:27 s15 kernel: oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user/doug/0,task=bla,pid=24349,uid=1000
Nov 11 16:08:27 s15 kernel: Out of memory: Killed process 24349 (bla) total-vm:32638768kB, anon-rss:15430324kB, file-rss:952kB, shmem-rss:0kB, UID:1000 pgtables:61218816kB oom_score_adj:0
Nov 11 16:08:27 s15 kernel: oom_reaper: reaped process 24349 (bla), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

Это все еще берет некоторое время для выполнения, но на порядке минут только.
использование mlock в программе C могло бы помочь, но я не попробовал его.

Мой тестовый компьютер является сервером, таким образом, я использую watch -d free -m для контроля прогресса.

Читатели: Питание с OOM несколько опасно. При чтении всех этих ответов и комментариев Вы отметите некоторый сопутствующий ущерб и несоответствия. Мы не можем управлять, когда другие задачи могли бы спросить некоторое время больше памяти, которая могла быть в только неправильное время. Соблюдите осторожность и рекомендуйте перезагрузку компьютера после подобных тестов.

7
ответ дан 23 November 2019 в 05:24

В терминале введите "Python"

Затем копия и вставьте этот код и нажмите Enter:

var=[]
for x in xrange(99999999999):
    var.append(str(x))

Затем сделайте:

"cat /var/log/messages" and you'll find something like:
Nov 12 11:48:05 TestVM kernel: Out of memory: Kill process 1314 (python) score 769 or sacrifice child
Nov 12 11:48:05 TestVM kernel: Killed process 1314 (python) total-vm:1001264kB, anon-rss:802972kB, file-rss:60kB, shmem-rss:0kB
Nov 12 11:48:49 TestVM kernel: python[1337]: segfault at 24 ip 00007f2ad140c0da sp 00007ffee8c11820 error 6 in libpython2.7.so.1.0[7f2ad1382000+17e000]
3
ответ дан 23 November 2019 в 05:24

Пересмотренный ответ

Мой первоначальный ответ занял 1/2 час для выполнения и был отброшен в этом пересмотре:

ls -d /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*

я приму чужой ответ как более быстрый способ вызов oom-killer из командной строки. Как пересмотренный ответ я объясню, как получить соответствующие oom-уничтожающие детали от journalctl и что они имеют в виду.

<час>

Этот более эффективный ответ [1 114] mjoao для израсходования RAM:

logger --tag="kernel" "Start for oom-killer"; a=""; for b in {0..99999999}; do a=$b$a$a$a$a$a$a; done

Эти logger команда предварительно ожидалась для предоставления метки времени в journalctl для того, когда пищевой процесс RAM запускается.

После того, как oom-уничтожитель закончен, откройте новый терминал и тип oomlog (содержание сценария позже):

$ oomlog
Nov 12 12:29:23 alien kernel[19202]: Start for oom-killer
Nov 12 12:30:02 alien kernel: 31981 total pagecache pages
Nov 12 12:30:02 alien kernel: 11627 pages in swap cache
Nov 12 12:30:02 alien kernel: Swap cache stats: add 10739122, delete 10727632, find 8444277/9983565
Nov 12 12:30:02 alien kernel: Free swap  = 0kB
Nov 12 12:30:02 alien kernel: Total swap = 8252412kB
Nov 12 12:30:02 alien kernel: 2062044 pages RAM
Nov 12 12:30:02 alien kernel: 0 pages HighMem/MovableOnly
Nov 12 12:30:02 alien kernel: 56052 pages reserved
Nov 12 12:30:02 alien kernel: 0 pages cma reserved
Nov 12 12:30:02 alien kernel: 0 pages hwpoisoned
Nov 12 12:30:02 alien kernel: [ pid ]   uid  tgid total_vm      rss nr_ptes nr_pmds swapents oom_score_adj name
Nov 12 12:30:02 alien kernel: [ 4358]  1000  4358  2853387  1773446    5578      13  1074744             0 bash
Nov 12 12:30:02 alien kernel: Out of memory: Kill process 4358 (bash) score 701 or sacrifice child
Nov 12 12:30:02 alien kernel: Killed process 4358 (bash) total-vm:11413548kB, anon-rss:7093784kB, file-rss:0kB, shmem-rss:0kB
Nov 12 12:30:03 alien kernel: oom_reaper: reaped process 4358 (bash), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

лучший ответ занимает 30 секунд для израсходования RAM, которая не является слишком быстрой (как tail /dev/zero) и не слишком медленной (как мой исходный ответ).

oomlog сценарий уплотняет много страниц [1 111] вывод в 16 строк.

oom-killer [pid] поля объяснены здесь :

  • pid идентификатор процесса.
  • идентификатор пользователя uid .
  • идентификатор группы Потока tgid.
  • использование виртуальной памяти total_vm (на страницах на 4 КБ)
  • Резидентное использование памяти rss (на страницах на 4 КБ)
  • записи nr_ptes Таблицы страниц
  • записи Подкачки swapents
  • oom_score_adj Обычно 0; более низкое количество указывает, что процесс, менее вероятно, умрет, когда уничтожитель OOM будет вызван.
<час>

oomlog колотят сценарий

#!/bin/bash

# NAME: oomlog
# PATH: $HOME/askubuntu/
# DESC: For: https://askubuntu.com/questions/1188024/how-to-test-oom-killer-from-command-line
# DATE: November 12, 2019.
# PARM: Parameter 1 can be journalctl boot sequence, eg -b-2 for two boots ago.
#       Defaults to -b-0 (current boot).

BootNo="-b-0"
[[ $1 != "" ]] && BootNo="$1"

# Get time stamp if recorded with `logger` command:
journalctl "$BootNo" | grep 'Start for oom-killer' | tail -n1
# Print headings for last oom-killer
journalctl "$BootNo" | grep '\[ pid ]' -B10 | tail -n11
# Get lat oom_reaper entry's PID
PID=$(journalctl "$BootNo" | grep oom_reaper | tail -n1 | cut -d' ' -f9)
# Print pid information
journalctl "$BootNo" | grep "$PID"']' | tail -n1
# Print summary infomation
journalctl "$BootNo" | grep oom_reaper -B2 | tail -n3
1
ответ дан 23 November 2019 в 05:24

Если Вы просто хотите инициировать oom-уничтожителя, просто увеличить размер "$a" экспоненциально, как так:

bash -c "for b in {0..99999999}; do a=$b$a; done"

, Если Вы хотите контролировать его живой, просто необходимо сделать вложенный цикл как:

for x in {1..200}; do echo "Round $x"; bash -c "for b in {0..99999999}; do a=$b$a; done"; done

нет никакой потребности скомпилировать что-либо. Bash может сделать это самостоятельно.

Ожидаемые Результаты:

kernel: Out of memory: Kill process 1439 (bash) score 777 or sacrifice child
kernel: Killed process 1439 (bash)

Примечание: К сожалению, у меня нет счета для регистрации этого как комментария.

1
ответ дан 23 November 2019 в 05:24

Другие вопросы по тегам:

Похожие вопросы: