OOM KillerまたはOut Of Memory Killerは、システムのメモリが非常に少ないときにlinuxカーネルが使用するプロセスです。 ...これにより、プロセスに割り当てられたメモリがアクティブに使用されるようになり、システムメモリの使用が最大化されます。
この自己回答形式の質問では、次のように質問されます。
自己応答でかかる1/2時間よりも速い方法が受け入れられます。
OOMキラーをすばやくトリガーするための鍵は、ディスクアクセスによって行き詰まるのを避けることです。そう:
スワップが使用されているときのOOMの動作を具体的にテストすることが目的でない限り、スワップを避けます。テストの前にスワップを無効にしてから、再度有効にすることができます。その後。 _swapon -s
_は、現在有効になっているスワップを示します。 _Sudo swapoff -a
_はすべてのスワップを無効にします。 _Sudo swapon -a
_は通常、それらを再度有効にするのに十分です。
非スワップディスクアクセスによるメモリアクセスの散在を回避します。そのグロビングベースの方法 は最終的に使用可能なメモリを使い果たします(十分に与えられます)ファイルシステム内のエントリ)、ただし、非常に多くのメモリが必要な理由は、ファイルシステムにアクセスして取得する情報を格納するためです。 SSDを使用している場合でも、スワップがオフになっている場合でも、ディスクからの読み取りに多くの時間が費やされる可能性があります。ディスクアクセスが散在しているメモリアクセスのOOM動作をテストすることが具体的な目標である場合、その方法は妥当であり、おそらく理想的です。それ以外の場合は、目標をはるかに早く達成できます。
スワップを無効にすると、物理ディスクからめったに読み取らないメソッドは非常に高速になります。これには_tail /dev/zero
_( found by falstaff 、 commented上記Doug Smythies )キャラクターデバイス_/dev/zero
_から読み取りますが、その「デバイス」はnullバイト(つまり、すべてゼロのバイト)を生成するだけで、デバイスノードが開かれると、物理ディスクアクセスを一切含みません。その方法は、tail
が入力の末尾の行を探すので機能しますが、ゼロのストリームには改行文字が含まれていないため、破棄される行はありません。
あなたが インタプリタ言語でワンライナーを探している であり、メモリをアルゴリズムで割り当てて設定する場合、あなたは運がいいです。ほぼすべての汎用インタープリター言語では、他の方法を使用せずに、大量のメモリを割り当ててそこに書き込むのは簡単です。これは、_tail /dev/zero
_とほぼ同じ速度であると思われるPerlの1行です(私は広範囲にベンチマークしていませんが)。
_Perl -wE 'my @xs; for (1..2**20) { Push @xs, q{a} x 2**20 }; say scalar @xs;'
_
4 GiB=のRAMが搭載された古いマシンでスワップがオフになっていると、それと_tail /dev/zero
_の両方を実行するたびに約10秒かかりました。はるかに多くのRAMそれよりも。目標が簡潔であれば、Perl
コマンドをはるかに短くすることができます。
そのPerlワンライナーは(_q{a} x 2**20
_)の別々の適度に長い文字列(それぞれ約100万文字)を繰り返し生成し、配列(_@xs
_)に格納することでそれらをすべて保持します。テスト用に数値を調整できます。使用可能なメモリをすべて使用しない場合、ワンライナーは作成された文字列の総数を出力します。 OOMキラーがPerl
を強制終了すると仮定すると、上記の正確なコマンドと邪魔するリソースクォータがないため、実際には常にそうであると私は信じています-その場合、シェルはKilled
を表示するはずです。次に、あらゆるOOMの状況と同様に、dmesg
に詳細があります。
私はその方法が好きですが、それは Doug Smythiesの回答 にあるような、Cプログラムの作成、コンパイル、および使用に関する有用なものを示しています。高水準のインタプリタ言語では、メモリの割り当てとメモリへのアクセスは別のもののようには感じられませんが、Cでは気づき、必要に応じてそれらの詳細を調査できます。
最後に、OOMキラーが実際にプログラムを強制終了したものであることを常に確認する必要があります。チェックする1つの方法は、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キラーをトリガーしませんでした。より一般的に言えば:
malloc()
などのライブラリ機能を介して)実行される簿記で発生します。 bash
配列(実際には二重リンクリストとして実装されています)でのテスト中にbash
が終了し、割り当て9バイトが失敗したことを示すエラーメッセージが表示されたときに、これが今日起こったのではないかと思います。OOMキラーは、意図的にトリガーするよりも、誤ってトリガーする方がはるかに簡単です。
OOMキラーを意図的にトリガーしようとする場合、これらの問題を回避する1つの方法は、メモリを要求しすぎることから始めて、次第に小さくすることです Doug SmythiesのCプログラム と同じです。別の方法は、適度なサイズのメモリのチャンク全体を割り当てることです。これは、上記のPerlワンライナーが行うことです。100万文字の文字列(および舞台裏での追加のメモリ使用量)は特に負担になりません。まとめると、1メガバイトの購入がすべて加算されます。
この答えは、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
実行にはしばらく時間がかかりますが、数分程度です。
Cプログラムでのmlock
の使用は役立つかもしれませんが、私は試しませんでした。
テストコンピューターはサーバーなので、watch -d free -m
進行状況を監視します。
ターミナルで「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]
Oom-killerをトリガーするだけの場合は、次のように「$ 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
何もコンパイルする必要はありません。バッシュはそれを単独で行うことができます。
予期された結果:
kernel: Out of memory: Kill process 1439 (bash) score 777 or sacrifice child
kernel: Killed process 1439 (bash)
注:残念ながら、これをコメントとして投稿するためのスコアはありません。
私の最初の答えは実行するのに1/2時間かかりました、そしてこのリビジョンで落とされました:
ls -d /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*
コマンドラインからoom-killer
を呼び出すより高速な方法として、他の誰かの回答を受け入れます。改訂された回答として、journalctl
から関連するoom-killerの詳細を取得する方法とその意味を説明します。
logger --tag="kernel" "Start for oom-killer"; a=""; for b in {0..99999999}; do a=$b$a$a$a$a$a$a; done
logger
コマンドは、RAM食べるプロセスが開始したときのタイムスタンプをjournalctl
に与えるために追加されました。
Oom-killerが終了したら、新しいターミナルを開いて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
スクリプトは、journalctl
出力の多くのページを16行に圧縮します。
oom-killer
[pid]フィールドの説明 here :
- pidプロセスID。
- uidユーザーID。
- tgidスレッドグループID。
- total_vm仮想メモリの使用(4 kBページ)
- rss常駐メモリの使用(4 kBページ)
- nr_ptesページテーブルエントリ
- swapentsエントリをスワップ
- oom_score_adj通常0;数値が小さいほど、OOMキラーが呼び出されたときにプロセスが停止する可能性が低くなります。
#!/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