問題:RAMは空いているのにコマンドが失敗するターミナルセッション中に、突然 ls、top、htop などの基本コマンドが動かなくなることがあります。期待する出力の代わりに、次のような頑固なエラーが返されます:
bash: fork: Cannot allocate memory
当然、RAMの使用状況を確認しますが、サーバーにはまだギガバイト単位の空きメモリがあります。このエラーは非常に誤解を招きやすいことで知られています。物理RAMが枯渇したことを意味することはほとんどありません。その代わり、通常はLinuxカーネルがプロセスID(PID)の最大数に達したか、特定のユーザーがプロセス上限に引っかかったことを示しています。
なぜこのエラーが発生するのかLinuxでは、すべてのタスク、スレッド、プロセスに一意のPIDが必要です。カーネルは同時に管理できるPIDの総数に上限を設けています。システムがこの上限に達すると、新しいプロセスを「fork」(生成)できなくなります。主な原因は以下の通りです:
- PIDの枯渇: システム全体の
pid_max上限(デフォルトでは32,768に設定されていることが多い)に達した。- ユーザー制限: 特定のユーザーが最大プロセス数のulimitに達した。- スレッドリーク: バグのあるアプリケーションや「fork爆弾」が、数千ものスレッドを制御不能に生成している。- コンテナの制限: Dockerコンテナまたはsystemdスライスが特定のタスク上限で制限されている。## 緊急トラブルシューティング新しいコマンドを実行できない状態になった場合、すぐにPIDを解放する必要があります。ターミナルが使用可能であれば、システム全体の現在のプロセス数を確認してください:
ps -eLf | wc -l
そのコマンドも同じforkエラーで失敗する場合は、不要なSSHセッションを閉じるか、クラウドコンソールや管理パネルから重いサービスを停止してみてください。root権限がある場合は、PID上限を一時的に2倍にして即座に余裕を確保できます:
sudo sysctl -w kernel.pid_max=65536
または、現在のシェルセッションのプロセス上限を引き上げます:
ulimit -u 4096
恒久的な解決策### 1. グローバルPID上限を引き上げる複数のJavaアプリやマイクロサービスを実行するような高並列環境では、デフォルトの32k PIDでは不足することがよくあります。まず、現在の上限を確認します:
cat /proc/sys/kernel/pid_max
恒久的な変更を行うには、/etc/sysctl.conf ファイルを編集します:
sudo nano /etc/sysctl.conf
ファイルの末尾に以下の行を追加します(必要に応じて64kまたは128kに設定):
kernel.pid_max = 65536
再起動せずに変更をすぐに反映させます:
sudo sysctl -p
2. ユーザー固有の制限を調整する(ulimit)システム全体の上限は問題ないのに、www-data や mysql などの特定のサービスユーザーが壁に当たっている場合があります。セキュリティ制限の設定ファイルを修正します:
sudo nano /etc/security/limits.conf
以下の行を追加して、すべてのユーザーのプロセス数(nproc)を増やします。特定のユーザーにのみ適用する場合は * をユーザー名に置き換えてください:
* soft nproc 65535
* hard nproc 65535
3. systemdサービスのスロットリングを修正する現代のLinuxディストリビューションはsystemdを使用しており、グローバル設定に関わらず、サービスに独自の制限を課すことがよくあります。Nginxなど特定のサービスが失敗している場合は、オーバーライドファイルを編集します:
sudo systemctl edit my_service_name.service
エディタに以下の行を挿入します:
[Service]
TasksMax=infinity
デーモンをリロードしてサービスを再起動し、修正を適用します:
sudo systemctl daemon-reload
sudo systemctl restart my_service_name.service
4. プロセスリークを特定する再起動後もPID数が増加し続ける場合は、プロセスリークが発生している可能性が高いです。次のコマンドを使って、最も多くのPIDを消費しているユーザーを確認します:
ps -efL | awk '{print $1}' | sort | uniq -c | sort -nr
特定のユーザーが10,000以上のプロセスを所有している場合は、そのユーザーのアクティブなタスクを調査してください。pkill を使ってすばやくクリアできます:
pkill -u username_here

