5

5 ~ 6 個のスレッドを作成するアプリケーションを考えてみましょう。サイクル内の各スレッドは、5 MB のページ サイズに MappedByteBuffer を割り当てます。

MappedByteBuffer b = ch.map(FileChannel.MapMode.READ_ONLY, r, 1024*1024*5);

遅かれ早かれ、アプリケーションが大きなファイルを処理すると、oom がスローされます

java.io.IOException: Map failed  at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:758)
Caused by: java.lang.OutOfMemoryError: Map failed
        at sun.nio.ch.FileChannelImpl.map0(Native Method)
        at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:755)

仕様によると、MappedBuffer は GC 自体であるとすぐにダイレクト メモリを破棄する必要があります。問題は、MappedBuffer の GC 処理が遅すぎて、後でダイレクト メモリが終了したことです。

この状況を回避するには?おそらくMappedBufferを暗黙的に破棄するか、MappedBufferのある種のプールを使用すると言います

4

4 に答える 4

6

マップされたバイトバッファを直接クリーンアップすることで、GCをトリガーする必要をなくすことができます。

public static void clean(ByteBuffer bb) {
    if(bb == null) return;
    Cleaner cleaner = ((DirectBuffer) bb).cleaner();
    if(cleaner != null) cleaner.clean();
}

破棄する前にこれを呼び出すと、仮想メモリが不足することはありません。

おそらく、より大きなByteBufferの作成頻度を減らすことができます(ファイルの数が多い場合を除く)MappedByteBufferの作成は無料ではありません(一部のマシンでは約50マイクロ秒かかります)

于 2011-12-18T22:10:19.750 に答える
2

たぶん、WeakHashMapそれらをプールするMappedBuffersとうまくいくでしょう。

ただし、根本的な原因を推測する前に、アプリをVisual VM 1.3.3に接続し、すべてのプラグインをインストールして、OOM エラーの原因を正確に確認できるようにすることをお勧めします。これらの MappedBuffers がそれを行っていると推測していますが、5-6 スレッドに対してそれぞれ 5MB しかなく、合計で 25-30MB です。

推測よりもデータを持っているほうがよい。Visual VM がそれを取得します。

于 2011-12-18T16:47:08.990 に答える
0

MappedBuffer は、GC 自体であるとすぐにダイレクト メモリを破棄する必要があります。

私が見る限りどこにもそうは書いてありません。リリースされないという長年の Bug Parade アイテムがあります。

それはこう言っています:

したがって、ダイレクト バッファは、主に大規模で長寿命のバッファに割り当てることをお勧めします。

于 2011-12-19T05:51:01.570 に答える