5

私は、メモリ内のかなり複雑でビッグデータ構造(数GB)にデータを準備してディスクにシリアル化するJavaプログラムと、メモリ内のシリアル化されたデータ構造を読み戻す別のプログラムを持っています。デシリアライズのステップがかなり遅く、CPUにバインドされていることに驚いた。(100%のCPU使用率ですtopが、で読み取るのは3〜5 MB / sのみiotopです。これは、ハードドライブでのシーケンシャル読み取りの場合は非常に低くなります)。CPUはかなり最近のものであり(Core i7-3820)、構造はメモリに収まり、スワップスペースは構成されていません。

なんでそうなの?CPUをボトルネックにしないJavaでオブジェクトをシリアル化する別の方法はありますか?

重要な場合の逆シリアル化コードは次のとおりです。

FileInputStream f = new FileInputStream(path);
ObjectInputStream of = new ObjectInputStream(f);
Object obj = of.readObject();
4

2 に答える 2

4

デシリアライズはかなり高価です。一般的な逆シリアル化を使用すると、多くのリフレクションとオブジェクトの作成が使用されます。

より高速で、ほとんどの場合、リフレクションの代わりに生成されたコードを使用する代替案がたくさんあります。

http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

最も速いものの1つは、Externalizableを使用することであり、これはオプションである可能性があります。これは、オブジェクトのシリアル化と逆シリアル化のためのカスタムメソッドを追加することを意味します。

私ははるかに高速なアプローチを作成しましたが、これにより、オブジェクトをリサイクルしたり、ファイル内のデータをインプレースで使用したりすることでオブジェクトを作成することを回避できます(つまり、オブジェクトを逆シリアル化する必要はありません)。

于 2012-04-10T15:34:55.907 に答える
2

プロファイラーでこれを見たり、オブジェクトの構造の実際の階層についてよく知っていないと言うのは難しいですが、それが「かなり複雑」で「数GB」のオーダーであれば、おそらくあなたはおそらく何千もの個々のオブジェクトを処理します。

ここでの私の最も良い推測は、あなたのパフォーマンスがJavaReflectionによって殺されているということです。リフレクションは、ストリームからオブジェクトを構築するために使用されます。これは、コード内でコンストラクターを直接呼び出すよりも少なくとも2桁遅いことが知られています。したがって、オブジェクトに大量の「小さな」オブジェクトがある場合、Reflectionはそれらの再構築に多くの時間を費やします。

(まだ行っていない場合)試すことができる1つのことは、各Serializableクラスの上部に次の行を宣言することです。

private static final long serialVersionUID = [some number]L;

このIDを宣言しない場合、Javaはそれを計算する必要があるため、宣言することでCPUサイクルを節約できます。

詳細については、以下を参照してください。

http://oreilly.com/catalog/javarmi/chapter/ch10.html

于 2012-04-10T15:35:50.740 に答える