29

Linux の Jetty 7.0.1 で実行されている Java Web アプリケーションでファイル記述子のリークをデバッグしようとしています。

アプリは 1 か月ほど正常に実行されていましたが、開いているファイルが多すぎるためにリクエストが失敗し始め、Jetty を再起動する必要がありました。

java.io.IOException: Cannot run program [external program]: java.io.IOException: error=24, Too many open files
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:459)
    at java.lang.Runtime.exec(Runtime.java:593)
    at org.apache.commons.exec.launcher.Java13CommandLauncher.exec(Java13CommandLauncher.java:58)
    at org.apache.commons.exec.DefaultExecutor.launch(DefaultExecutor.java:246)

最初は、外部プログラムを起動するコードに問題があると思っていましたが、それはcommons-execを使用しており、問題はありません。

CommandLine command = new CommandLine("/path/to/command")
    .addArgument("...");
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
Executor executor = new DefaultExecutor();
executor.setWatchdog(new ExecuteWatchdog(PROCESS_TIMEOUT));
executor.setStreamHandler(new PumpStreamHandler(null, errorBuffer));
try {
    executor.execute(command);
} catch (ExecuteException executeException) {
    if (executeException.getExitValue() == EXIT_CODE_TIMEOUT) {
        throw new MyCommandException("timeout");
    } else {
        throw new MyCommandException(errorBuffer.toString("UTF-8"));
    }
}

サーバーで開いているファイルを一覧表示すると、多数の FIFO が表示されます。

# lsof -u jetty
...
java    524 jetty  218w  FIFO        0,6      0t0 19404236 pipe
java    524 jetty  219r  FIFO        0,6      0t0 19404008 pipe
java    524 jetty  220r  FIFO        0,6      0t0 19404237 pipe
java    524 jetty  222r  FIFO        0,6      0t0 19404238 pipe

Jetty の起動時には FIFO が 10 個しかありませんが、数日後には数百個になります。

この段階では少し曖昧であることは承知していますが、次にどこを見るべきか、またはこれらのファイル記述子に関する詳細情報を取得する方法について何か提案はありますか?

4

6 に答える 6

26

問題は、Java アプリケーション (または使用しているライブラリ) に起因します。

まず、出力全体 (StreamGobbler の場合は Google) を読み、pronto!

Javadocは次のように述べています。

親プロセスは、これらのストリームを使用して、サブプロセスに入力をフィードし、サブプロセスから出力を取得します。一部のネイティブ プラットフォームでは、標準の入力ストリームと出力ストリームに対して限られたバッファー サイズしか提供されないため、サブプロセスの入力ストリームの書き込みまたは出力ストリームの読み取りが迅速に行われないと、サブプロセスがブロックされたり、デッドロックが発生したりする可能性があります。

次にwaitFor()プロセスを終了します。次に、入力ストリーム、出力ストリーム、およびエラー ストリームを閉じる必要があります。

最後に destroy()あなたのプロセス。

私の情報源:

于 2011-05-11T12:22:42.963 に答える
7

ファイルリークなどの根本原因の問題を調査する以外に、「開いているファイル」の制限を正当に増やし、再起動後もそれを維持するために、編集を検討してください。

/etc/security/limits.conf

このようなものを追加することで

jetty soft nofile 2048
jetty hard nofile 4096

この場合、「jetty」はユーザー名です。limits.conf の詳細については、http://linux.die.net/man/5/limits.confを参照してください。

ログオフしてから、再度ログインして実行します

ulimit -n

変更が行われたことを確認します。このユーザーによる新しいプロセスは、この変更に準拠する必要があります。このリンクは、すでに実行中のプロセスに制限を適用する方法を説明しているようですが、私は試していません。

デフォルトの制限 1024 は、大規模な Java アプリケーションでは低すぎる場合があります。

于 2014-07-31T17:10:08.760 に答える
7

Linux で実行しているため、ファイル記述子が不足していると思われます。ulimitをチェックしてください。問題を説明する記事は次のとおりです。 http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

于 2010-01-11T20:38:24.093 に答える
5

アプリの性質はわかりませんが、接続プールのリークが原因でこのエラーが何度も発生するのを見たので、チェックする価値があります。Linux では、ソケット接続はファイル記述子とファイル システム ファイルを消費します。ちょっとした考え。

于 2010-01-11T20:53:40.940 に答える
1

fds は自分で処理できます。Java の exec は Process オブジェクトを返します。プロセスがまだ実行されているかどうかを断続的に確認します。完了したら、プロセスの STDERR、STDIN、および STDOUT ストリームを閉じます (例: proc.getErrorStream.close())。そうすることで漏れが軽減されます。

于 2011-03-24T13:24:49.520 に答える
-1

この問題は、多くのファイルに同時にデータを書き込んでおり、オペレーティング システムで開いているファイルの制限が固定されている場合に発生します。Linux では、開いているファイルの制限を増やすことができます。

https://www.tecmint.com/increase-set-open-file-limits-in-linux/

Linux で開いているファイル数の制限を変更するにはどうすればよいですか?

于 2018-06-06T12:43:07.887 に答える