私は非常に基本的なものに苦労してきました。問題は、長いポーリングに Jetty の継続を使用することに関連しています。
簡単にするために、アプリケーション固有のコードをすべて削除し、単純な継続関連のコードを残しました。
以下に、サーブレットの doPost メソッドを貼り付けます。専門家のガイダンスが必要な重要な質問は、
- 以下のコード ブロックをそのまま実行し、約 200 バイトのポスト ボディを運ぶポスト リクエストを発行すると、500 の長いポーリング接続のメモリ量は約 20 MB になります。
- 強調表示されたブロックを「メモリ フットプリントを減らす :: コメント ブロックを下に」とコメントすると、メモリ フット プリントは 7 MB になります。
どちらの場合も、システムが安定するのを待ち、GC を複数回呼び出してから、jConsole を介してメモリを読み取ります。正確ではありませんが、違いは非常に大きく説明可能であるため、100バイト程度の精度は問題になりません。
サーバーが 100K 接続を保持する必要があることを考えると、私の問題は爆発します。そしてここで、この説明のつかないサイズの増加は、最終的に GB 近くの余分なヒープを使用することにつながります。
(ストリームから読み取られたものでさえ doPost メソッドの範囲外に保存されていない場合、この余分なヒープ使用の原因は何ですか。しかし、それでもヒープに追加されます....何が欠けていますか?)
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
Continuation cc = ContinuationSupport.getContinuation(req);
//if continuation is resumed, then send an answer back with
//hardcoded answer
if (cc.isResumed()) {
String myJson = "{\"1\",\"2\"}";
res.setContentType("application/json");
res.setContentLength(myJson.length());
PrintWriter writer = res.getWriter();
writer.write(myJson);
writer.close();
}
// if it is the first call to doPost ( not reentrant call )
else if (cc.isInitial()) {
//START :: decrease memory footprint :: comment this block :: START
// store the json from the request body in a string
StringBuffer jsonString = new StringBuffer();
String line = null;
BufferedReader bufferedReader = req.getReader();
while ((line = bufferedReader.readLine()) != null) {
jsonString.append(line);
}
//here jsonString was parsed and some values extracted
//though that code is removed for the sake of this publish
// as problem exists irrespective...of any processing
line = null;
bufferedReader.close();
bufferedReader = null;
jsonString = null;
// END :: decrease memory footprint :: comment this block :: END
cc.setTimeout(150000);
cc.suspend();
}
}