web-dev-qa-db-ja.com

(過剰なメモリ割り当てが原因で)スラッシングを引き起こしているプロセスをすばやく停止するにはどうすればよいですか?

私たちは皆それを経験しました-あるプログラムは大量のメモリを必要とする何かをするように頼まれます。このすべてのメモリを忠実に割り当てようとすると、システムはすぐにスラッシングを開始し、無限にスワップし、速度が低下したり応答しなくなったりします。

私は最近、Matlabスクリプトが途方もなく巨大なマトリックスを割り当てようとしたためにUbuntuラップトップでこれを経験しました。約5分以上のスラッシングの後、コンソールにCtrl-F1を押して、Matlabを強制終了することができました。むしろ、システムをすぐに制御でき、問題のあるプロセスを強制終了できるホットキーが必要です。または、おそらく、そのような大きなバッファの割り当てを黙って拒否します。

  1. 過度のスワッピングが原因で応答しなくなったり、極端に遅くなったりしたLinuxシステムの制御を取り戻すための最も簡単な方法は何ですか?

  2. プロセスが割り当てを試みることができるメモリの量を制限するなどして、そもそもそのようなスワッピングが発生するのを防ぐ効果的な方法はありますか?

19
nibot

Alt-SysRq-Fを押して、最も多くのメモリを使用しているプロセスを強制終了します。

  • SysRqキーは通常、Printキーにマップされます。
  • グラフィカルデスクトップを使用している場合、Alt-SysRqを押す場合は、Ctrl-Alt-SysRq-Fを押す必要があります。別のアクション(スナップショットプログラムなど)をトリガーします。
  • ラップトップを使用している場合は、ファンクションキーも押す必要がある場合があります。
  • 詳細については、 ウィキペディアの記事 をお読みください。
13
joke

この目的のためにスクリプトを作成しました- https://github.com/tobixen/thrash-protect

私はこのスクリプトを本番サーバー、ワークステーション、ラップトップで実行して成功しました。このスクリプトはプロセスを強制終了しませんが、一時的に一時停止します-この単純なスクリプトがなかった場合、スラッシングが原因で制御を失ったと確信している状況が後でいくつかありました。 「最悪の」場合、問題のあるプロセスは大幅に遅くなり、最終的にカーネル(OOM)によって強制終了されます。「最良の」場合、問題のあるプロセスは実際に完了します...いずれの場合も、サーバーまたはワークステーション状況の調査が容易になるように、比較的応答性が高くなります。

もちろん、「メモリを追加購入する」または「スワップを使用しない」は、「スラッシングを回避する方法」という質問に対する2つの代替の、より伝統的な回答ですが、一般的にはうまく機能しない傾向があります(メモリを追加すると、些細なことではありませんが、不正なプロセスは、インストールされているメモリの量に関係なくすべてのメモリを消費する可能性があり、バッファリング/キャッシュに十分なメモリがない場合、スワップがなくてもスラッシングの問題が発生する可能性があります。スラッシュプロテクトとたくさんのスワップスペースをお勧めします。

5
tobixen
  1. 過度のスワッピングが原因で応答しなくなったり、極端に遅くなったりしたLinuxシステムの制御を取り戻すための最も簡単な方法は何ですか?

すでに上記でAlt-SysRq-Fで回答済み

  1. プロセスが割り当てを試みることができるメモリの量を制限するなど、そもそもそのようなスワッピングが発生するのを防ぐ効果的な方法はありますか?

私はこの第2部に答えています。はい、ulimitは、単一のプロセスを制限するのに十分に機能します。あなたはできる:

  • 制御不能になる可能性が高いことがわかっているプロセスにソフト制限を設定する
  • 追加の保険が必要な場合は、すべてのプロセスにハード制限を設定します

また、簡単に述べたように:

CGroupsを使用して、リソースの使用を制限し、そのような問題を防ぐことができます

実際、cgroupはより高度な制御を提供しますが、私の意見では現在、構成がより複雑です。

オールドスクールulimit

一度オフ

簡単な例を次に示します。

_$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)
_

それ:

  • 全体的なメモリ使用量のソフト制限を1GBに設定します(ulimitはkB単位の制限を想定しています)
  • 再帰的なbash関数呼び出しr2(){ r2 $@$@;};r2 r2を実行します。これは、スタックメモリを要求している間、CPUとRAMを無限に倍増することにより、指数関数的に噛み砕きます。

ご覧のとおり、1GB以上をリクエストしようとすると停止しました。

_-v_は、仮想メモリの割り当て(合計、つまり物理+スワップ)で動作することに注意してください。

恒久的な保護

仮想メモリの割り当てを制限するために、asは_-v_の_limits.conf_と同等です。

私は、単一の不正なプロセスから保護するために次のことを行います。

  • すべてのプロセスにハードアドレス空間の制限を設定します。
  • _address space limit = <physical memory> - 256MB_。
  • したがって、貪欲なメモリ使用またはアクティブループとメモリリークを伴う単一のプロセスがすべての物理メモリを消費することはありません。
  • 256MBのヘッドルームは、sshまたはコンソールでの重要な処理のためにあります。

一発ギャグ:

_$ Sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"
_

検証するために、これは次の結果になります(たとえば、16GBシステムの場合)。

_$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960
_

ノート:

  • 単一のプロセスがメモリの使用で過剰になるのを軽減するだけです。
  • スラッシングを引き起こす大量のメモリプレッシャーを伴うマルチプロセスワークロードを防ぐことはできません(cgroupsがその答えです)。
  • Limits.confでrssオプションを使用しないでください。新しいカーネルでは尊重されていません。
  • 保守的です。
    • 理論的には、プロセスは投機的に大量のメモリを要求できますが、サブセットのみをアクティブに使用します(より小さなワーキングセット/常駐メモリの使用)。
    • 上記のハード制限により、そのようなプロセスは中止されます(Linuxで仮想メモリのアドレス空間がオーバーコミットされている場合は、正常に実行されていたとしても)。

新しいCGroups

より詳細な制御を提供しますが、現在は使用がより複雑です。

  • Ulimitオファリングを改善します。
    • _memory.max_usage_in_bytes_は、物理メモリを個別に考慮および制限できます。
    • _ulimit -m_および/または_limits.conf_のrssは同様の機能を提供することを目的としていましたが、カーネルLinux 2.4.30以降は機能しません!
  • ブートローダーでいくつかのカーネルcgroupフラグを有効にする必要があります:_cgroup_enable=memory swapaccount=1_。
    • これは、Ubuntu16.04ではデフォルトでは発生しませんでした。
    • おそらく、追加のアカウンティングオーバーヘッドのパフォーマンスへの影響が原因です。
  • cgroup/systemdは比較的新しく、かなり変更されているため、アップストリームの流動性は、Linuxディストリビューションベンダーがまだ使いやすくしていないことを意味します。 14.04LTSと16.04LTSの間で、cgroupを使用するためのユーザースペースツールが変更されました。
    • cgmは、公式にサポートされているユーザースペースツールのようです。
    • systemdユニットファイルには、sshなどの重要なサービスに優先順位を付けるための事前定義された「ベンダー/ディストリビューション」のデフォルトがまだないようです。

例えば。現在の設定を確認するには:

_$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...
_

例えば。単一プロセスのメモリを制限するには:

_$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed
_

バックグラウンドプロセスとしてRAMを噛み砕いてから殺されるのを見るには:

_$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'
_

メモリ要求の指数関数的(2の累乗)の増加に注意してください。

将来的には、SSHやグラフィカルスタックなどの重要なものについて、「ディストリビューション/ベンダー」がcgroupの優先順位と制限を(systemdユニットを介して)事前構成し、メモリが不足しないようにすることを期待しましょう。

4
JPvRiel

あなたは押すことができるかもしれません Ctrl-z プログラムを一時停止します。次に、kill %1(またはジョブ番号が何であれ、PIDを使用できます)を実行できます。

ulimitコマンドを使用して、プロセスで使用可能なメモリの量を制限することができます。

CGroupsを使用して、リソースの使用を制限し、そのような問題を防ぐことができます。 https://en.wikipedia.org/wiki/Cgroups

1
1kenthomas

GUIに、フォーカスのあるアプリケーションにSIGSTOPを送信するためのホットキーがあればいいのですが。

常に古典的なxkillコマンドがあります(私のシステムのxorg-x11-apps-7.4-14.fc14.src.rpmから)。ターゲットウィンドウを強制終了する代わりにSIGSTOPを送信するクローンを作成することはそれほど難しくないはずです。

0
hlovdal