1

そう。私は Scala を使用していますが、比較的慣れていません (ほとんどが Python のやつです)。sbt 経由でコードをコンパイルして実行しています。現在 Java 6 を実行している Ubuntu ボックスを使用しています。2 つの CSV があります。それらを取得し、処理し、操作する必要があります。各 CSV は最大 250 MB です。これが機能する場合は、はるかに大きな CSV でこのプロセスを繰り返す可能性があります。

CSV を読み取り、必要なデータ構造に各行を書き込む関数を定義しました。各 CSV でこの関数を順番に呼び出します。問題は、最初の CSV では完全に (そして非常に迅速に) 返されるが、2 番目の CSV では常にjava.lang.OutOfMemoryError: GC overhead limit exceededエラーがスローされることです。

私はかなり多くのことを試しました。私のbuild.sbt定義javaOptions += "-Xmx20480m -XX:+HeapDumpOnOutOfMemoryError"; 私も使ってみまし-XX:-UseGCOverheadLimitたが、何の役にも立たないようです。私が読んでいる Java ドキュメントによると、このエラーは大量のシステム リソースがガベージ コレクションに費やされていることを示しています。私の関数がどこかでメモリをリークしているに違いないと思います。または、Scala を誤用しているに違いありませんが、方法がわかりません。

これが私の機能です:

def readAndProcessData(path: String) = {
    val fileLines = Source.fromFile(path).getLines.drop(1)
    val ret = mutable.Map[String, List[Tuple2[String, String]]]()

    def addRowToRet(row: String) = {
        val rowArray = row.split(",")
        if (!(ret contains rowArray(0))) {
            ret.update(rowArray(0), List[Tuple2[String, String]]())
        }
        ret(rowArray(0)) = Tuple2(rowArray(1), rowArray(2)) :: ret(rowArray(0))
    }

    for (row <- fileLines) {
        addRowToRet(row)
    }

    ret.map{tup => (tup._1 -> tup._2.sorted)}

}

ありがとう!

4

2 に答える 2

6

まず、フォークして実行しない場合は、フォークを有効にするか、sbt のメモリ制限を増やして、javaOptions 設定を削除します。ここでは、プログラムのメモリ使用動作と sbt のメモリ使用動作を混同しないように、フォークすることをお勧めします。

また、リソースが確実に解放されるように、作成している Source オブジェクトを閉じる必要があります。

ソート時など、一貫した場所でクラッシュしていますか? または、クラッシュはコード内のかなりランダムな場所で発生しますか?

あなたが読んでいるファイルは、ほとんどすべての文字が 8 ビットで表される ASCII や UTF8 などのエンコーディングであると想定しています。Java は 1 文字あたり 16 ビットを使用するため、Java 文字列に読み込むことでサイズが 2 倍以上になることに注意してください (「以上」は他のオーバーヘッドによるものです)。それ自体はあなたを圧倒するべきではありませんが、2 つの 250 MB のファイルをロードするまでに、おそらくデータ用に 1 GB 以上のメモリを消費することになります。

ファイル内の行数に対してキーはどの程度分散されていますか? 言い換えれば、ほぼすべてのライン、ラインの約半分、4 分の 1 などについて、マップにエントリがありますか? (エントリに関して)かなり大きなマップを持つ可能性があり、それに対して「マップ」操作を実行して値をソートすると、関数が返されて古いものが収集可能になるまで、そのうちの2つがメモリに残ります。 . 不変マップまたは Java 可変マップのラッパーを使用することもできます。Scala の変更可能なデータ構造は、対応する不変のものほど堅牢ではない場合があります。

また、scala.io.Source でうまくいったことは一度もありません。実際に十分なメモリが割り当てられていることをかなり確信しているにもかかわらず、それでも失敗する場合は、Java の IO ライブラリを使用するようにドロップダウンしてみてください。

最後に、いくつかの設定を確認して少し突っ込んでもうまくいかない場合は、VisualVMなどのメモリ プロファイラーを接続する必要があります。それは、変更を加えて推測とチェックを行うのではなく、問題が実際にどこにあるのかを突き止めることに成功したということです。

于 2013-04-12T14:02:15.333 に答える