プロセスで使用可能なメモリの量を制限するにはどうすればよいですか?


11

私は外出先でプログラムを開発しています。非常に大量のメモリ(8Gの物理メモリを搭載したマシンでは>> 10G)が割り当てられ、システムが応答しなくなることがあります。プロセスが割り当てることができるメモリの量を制限したいのですが。これを行う通常の方法は次のとおりです。

ulimit -m 4000000 ; ./myprogram

... 4GBを超えるメモリを使用しようとすると、プログラムが強制終了されます。

OS X El Capitanでは、これは効果がないようです。でもulimit -m 1(メモリのちょうど1kBのにすべてのプログラムを制限すること!)は無効です。

特定のプロセスで使用可能なメモリの上限を設定するにはどうすればよいですか?


あなたが言うとき私がこれを行う通常の方法は、どういう意味ですか?具体的には、とき、あなたは通常、これを行うのですか?そしてそれを行うとき、それはMac OS X El Capitan内または別の環境内を意味するのですか?あなたがそれをうまく使ったときの例を挙げられますか?基本的に、私はこのプロセスが正常に機能するかどうかを明確にしようとしていますが、この特定のプログラムでは機能しないのですか?またはそれはあなたのためにまったく機能していませんが、あなたはそれがすべきだと思いますか?
Monomeeth

1
「これを行う通常の方法」とは、Unixの他のフレーバーでこれを行う方法を意味します。ulimit -mLinux(> 2.4.30)では動作しないことを発見しましたがulimit -v、期待どおりに動作します。(同様ulimit -mulimit -vOS Xにも影響がないようです。)
cpcallen 2017年

作成しているプログラムでメモリリークが発生し、ガベージコレクションを改善する必要があるようです。外出先でのメモリ管理について読みましたか?
トッドダブニー

1
いいえ、メモリリークではありません。潜在的に非常に大きな状態空間をグラフで検索するだけです。さまざまな内部構造が大きくなりすぎた場合に検索を中止するコードを追加することもできますが、シェルの1ライナーを使用して同じこと(マシンが大きな入力に押し込まれるのを防ぐ)ができると期待していました。
cpcallen 2017

回答:


1

メモリ使用量を制限するには、Ex post factoとpreemptiveの2つの方法があります。つまり、プログラムが大きくなりすぎた後にプログラムを強制終了するか、そもそもプログラムが大きくなりすぎないようにプログラムすることができます。

事後的なアプローチを主張する場合は、次のBashスクリプトを使用できます。このスクリプトは、最初にプロセスID pidのプロセスが使用しているメモリの量(「常駐セットサイズ」で定義)を見つけ、grepを使用してすべての非数値データをフィルターで除外し、その量を変数nとして保存します。次に、スクリプトは、nが指定したxより大きいかどうかを確認します。そうである場合、プロセスID pidのプロセスが強制終了されます。

ご注意ください:

  1. <pid>プログラムのプロセスIDに置き換える必要があります。
  2. <x>プログラムで超過させたくないrss = "常駐セットサイズ"(つまり、実メモリサイズ)に置き換える必要があります。

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

これをy秒ごとに実行する場合は、ループで閉じて、繰り返しごとにy秒待機するように指示します。を使用して同様のコマンドを書くこともできtopます。あなたの出発点はでしょうtop -l 1|grep "<pid>"|awk '{print $10}'

@kenorbの回答が私のスクリプトの助けになりました


私はそれが質問に答えると信じていますが、長期的には、手動のメモリ割り当てを使用してプリエンプティブなアプローチをとる方がプログラミング設計が優れていると思います。

まず、メモリ使用量が本当に問題なのか、ですって。Go ドキュメントには次のように記載されています。

Goメモリアロケーターは、仮想メモリの大きな領域を割り当ての領域として予約します。この仮想メモリは、特定のGoプロセスに対してローカルです。予約によってメモリの他のプロセスが奪われることはありません。

それでも問題があると思われる場合は、Cプログラミング言語で行われているように、メモリを手動で管理することをお勧めします。goはCで書かれているので、Cのメモリ管理/割り当てにアクセスする方法はあるのではないかと思いましたが、実際にあります。このgithubリポジトリを参照してください。

システムの標準Cアロケーターを介して手動でメモリ管理を行うことができます。これは、malloc、callocの上部にある薄いラッパーで、からは無料です。システムのこれらの関数の詳細については、man mallocを参照してください。このライブラリはcgoを使用します。

使用例は次のとおりです。

なぜこれが欲しいのですか?

プログラムがメモリ不足を引き起こしている場合、またはシステムのメモリが不足している場合は、メモリの割り当てと割り当て解除を手動で制御すると役立ちます。Goは割り当ての制御に役立ちますが、不要なデータの割り当てを明示的に解除することはできません。

これはより良い長期的な解決策のようです。

C(メモリ管理を含む)について詳しく知りたい場合 は、Cプログラミング言語が標準のリファレンスです。


私はメモリ使用量が本当に問題だと確信しています。プログラムが予期せず2倍以上の物理メモリサイズになると、マシンはページスラッシングのためにほぼ完全に応答しなくなりました。^ Cを押してからmacOSがマウスクリックへの応答を再開するまで、約1時間かかりました。その間、それが凍結されなかったという唯一の証拠は、ハードドライブの静かなノイズが急速にカチカチと音を立てていることでした。
cpcallen 2017年

これは実際にはおそらく妥当な解決策ですが、(Darwin以外の)UNIX OSのulimitとは異なり、killコマンドを正常に実行するために十分なメモリを適時に割り当てることができるかどうかに依存します。むしろ、カーネルによって強制されるプロセスサイズの制限が必要です。
cpcallen 2017年

@cpcallenが検索を行うと、「カーネルバージョンが2.4.30より新しいLinuxシステムでは、ulimitの-mパラメータは効果がありません。」OSXもこの変更に対応しているようです。-vオプションを試して、アドレス空間を制限してください
Evan Rosica

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.