[解決済み] ダイレクトバッファメモリ
質問事項
ウェブリクエストからかなり大きなファイルを返す必要があります。ファイルの大きさは約670mbです。ほとんどの場合、これは問題なく動作しますが、しばらくすると次のエラーがスローされます。
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:694) ~[na:1.8.0_162]
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) ~[na:1.8.0_162]
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) ~[na:1.8.0_162]
at sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:241) ~[na:1.8.0_162]
at sun.nio.ch.IOUtil.read(IOUtil.java:195) ~[na:1.8.0_162]
at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:159) ~[na:1.8.0_162]
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:65) ~[na:1.8.0_162]
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:109) ~[na:1.8.0_162]
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103) ~[na:1.8.0_162]
at java.nio.file.Files.read(Files.java:3105) ~[na:1.8.0_162]
at java.nio.file.Files.readAllBytes(Files.java:3158) ~[na:1.8.0_162]
ヒープサイズを4096mbに設定しましたが、これはこの種のファイルを扱うのに十分な大きさだと思われます。さらに、このエラーが発生したとき、私は現在の状態を分析するためにjmapでヒープダンプを取りました。その結果、2つのかなり大きなbyte[]が見つかりました。しかし、ヒープのサイズは1.6gb程度しかなく、設定されている4gbには程遠いのです。
他の方の回答によると( https://stackoverflow.com/a/39984276/5126654 )同様の質問で、私はこのファイルを返す前に手動gcを実行してみました。問題はまだ起こりますが、今はほんの少しです。問題はしばらくして発生しましたが、その後、同じリクエストを再び実行するのに疲れたとき、ガベージコレクションが問題の原因となっていたものを処理したように思えますが、問題は明らかにまだ発生することがあるので、これは十分ではありません。このメモリの問題を回避するための他の方法はありますか?
解決方法を教えてください。
で管理している実際のメモリバッファは
DirectByteBuffer
はヒープに割り当てられません。 Unsafe.allocateMemoryを使用して割り当てられ、それは"ネイティブメモリ"を割り当てます。そのため、ヒープサイズを増やしても減らしても効果はありません。
を検出した場合、GCは
DirectByteBuffer
が参照されなくなると
Cleaner
はネイティブメモリを解放するために使用されます。 ただし、これはコレクション後のフェーズで行われるため、ダイレクトバッファの需要/回転が大きすぎると、コレクターが追いつかなくなる可能性があります。 その場合、OOMEが発生します。
どうしたらいいのでしょうか?
AFAIKは、あなたができる唯一のことは、より頻繁なガベージコレクションを強制することです。 しかし、それはパフォーマンスに影響を与える可能性があります。 また、保証された解決策とは思えません。
本当の解決策は、別のアプローチをとることです。
ウェブサーバーから非常に大きなファイルを大量に提供していることがわかり、スタックトレースで
Files::readAllBytes
を使用してメモリにロードし、(おそらく)1つの
write
. おそらく、可能な限り最速のダウンロード時間を得るためにこうしているのでしょう。 これは間違いです。
-
あなたは多くのメモリ(の倍数)を縛り、ガベージコレクタにストレスを与えています。 これは、より多くのGC実行と時折のOOMEにつながっています。 また、サーバー上の他のアプリケーションに様々な影響を与える可能性があります。
-
ファイル転送のボトルネックは おそらく ディスクからデータを読み込む処理ではなく (本当のボトルネックは 通常 ネットワーク上のTCPストリームでデータを送信したり、クライアント側でファイルシステムに書き込んだりします)。
-
大きなファイルを順次読み込む場合、最近のLinux OSは通常、ディスクのブロック数を先読みして、ブロックを(OSの)バッファ・キャッシュに保持する方法を用います。 これによって
read
を呼び出すことができます。
ですから、このサイズのファイルでは、ファイルをストリーミングするのがベターなアイデアです。 大きな(数メガバイトの)
ByteBuffer
で、ループで読み書きを行う。
または
を使用してファイルをコピーします。
Files::copy(...)
(
ジャバドック
を使用すると、バッファリングがうまくいくはずです。
(また、Linux の
sendfile
のシステムコールです。 これは、ユーザースペースバッファに書き込むことなく、あるファイル記述子から別のファイル記述子へデータをコピーするものです)。
関連
-
[解決済み】"実引数リストと形式引数リストの長さが異なる"
-
[解決済み】不正なエスケープ文字"㊧"について
-
[解決済み] 解決済み】Javaが「型をインスタンス化できない」というエラーを返す [重複] [重複]
-
[解決済み】「error: '.class' expected」の意味と修正方法について
-
[解決済み】Eclipseで「公開型 <<classname>> は独自のファイルで定義する必要があります」エラー【重複あり
-
[解決済み] JavaでSSLピアが正しくシャットダウンされない
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] Androidでアプリケーションのメモリ使用量を確認するにはどうすればよいですか?
-
[解決済み] アプリケーションやプロセスの実際のメモリ使用量を測定するにはどうすればよいですか?
-
[解決済み】Node.jsのヒープがメモリ不足になる。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】javaで指定されたファイルが見つからない
-
[解決済み] hibernateでResultSetを抽出できない。
-
[解決済み】代入の左手は必ず変数 CharAt
-
[解決済み】Java、"変数名 "を変数に解決することができない
-
[解決済み】宣言されたパッケージが期待されるパッケージと一致しない ""
-
[解決済み] 解決済み】Javaが「型をインスタンス化できない」というエラーを返す [重複] [重複]
-
[解決済み】Java Error "Exception in thread "main" java.util.InputMismatchException" Array プログラムで発生。
-
[解決済み] JavaでSSLピアが正しくシャットダウンされない
-
[解決済み】Javaの未処理例外について
-
[解決済み] "java.nio.charset.MalformedInputException" を避けるために、すべての包括的なCharset。入力の長さ= 1"?