2

私は、一部のシステム間のやり取りのために GZIP 圧縮を実装する作業を行っています。システムは Java と C# の両方で記述されているため、標準ライブラリがサポートされているため、両方で GZIP ストリームが使用されました。

C# 側では、最大のテスト ファイル (圧縮されていない 70 MB) まですべてが機能しますが、Java でヒープ スペースが不足するという問題が発生します。IDE の容量までヒープ サイズを増やしてみましたが、問題はまだ解決されていません。

Java コードを最適化するためにいくつかの手順を実行しましたが、データがヒープに積み重なるのを防ぐ方法はないようです。これを処理する良い方法はありますか?以下は、現在の (より小さなストリームで作業している) ソリューションのサブセットです。

編集: @MarkoTopolnik からの推奨事項で変更された次のコード。変更により、クラッシュする前に 1,700 万文字が読み取られます。

public static String decompress(byte[] compressed, int size)
{
    GZIPInputStream decompresser;
    BufferedReader reader;
    char buf[] = new char[(size < 2048) ? size : 2048];
    Writer ret = new StringWriter( buf.length );

    decompresser = new GZIPInputStream( new ByteArrayInputStream( compressed ), buf.length );
    reader = new BufferedReader( new InputStreamReader( decompresser, "UTF-8" ) );

    int charsRead;
    while( (charsRead = reader.read( buf, 0, buf.length )) != -1 )
    {
        ret.write( buf, 0, charsRead );
    }
    decompresser.close();
    reader.close();

    return ret.toString();
}

で 760 万文字を少し超えるとコードが停止しArrayList、スタック トレースはArrayList.add()呼び出しが原因であることを示します (内部配列の展開をトリガーした後に失敗します)。

上記の編集されたコードでは、 への呼び出しがAbstractStringBuilder.expandCapacity()プログラムを強制終了します。

圧縮解除されたストリームから文字列を取得するために使用できる動的配列またはまったく異なるアプローチを実装するためのメモリ消費量の少ない方法はありますか? どんな提案でも大歓迎です!

4

2 に答える 2

3

全体をメモリに読み込むのではなく、チャンクします。一度に 1024 バイトのバッファを読み込み、すぐに書き出すようにします。これは、2 段階の読み取り/書き込みプロセスというよりも、Unix パイプに似ています。

于 2013-05-30T19:06:51.293 に答える