Javaのオブジェクトのサイズは、Habreで既に説明されています(たとえば
hereまたは
here) 。 多次元配列のサイズについて詳しく説明したいと思います。これは私にとっては予想外の単純なことです。
メモリから計算アルゴリズムを最適化する際、特定の(非常に合理的な)入力パラメーターを使用すると、float [500] [14761] [2]の配列が作成されるという事実に出会いました。 (HotSpot 1.6.0_26 32ビットで、誰かが興味を持っている場合)メモリをどれくらい取ることができますか? 概算で、
500 * 14 761 * 2 * sizeof(float) =
500 * 14 761 * 2 * 4 =
59 044 000バイトと何らかのオーバーヘッドを推定しました。 実際にチェックすることにしたので、
Eclipse Memory Analyzerを使用しました(信じられないほど魔法のようなものをお勧めします!)。この配列の「保持ヒープ」は
206 662 016バイトです。 良いオーバーヘッド-350%。 なぜそれが起こったのか見てみましょう。
私はインターネットでこの主題について書かれていることを検索し、英語で「
Java配列のメモリ使用量を計算する方法 」というかなり理解しやすい記事に出会いました。 簡単に言うと、プレゼンテーションの本質は次のとおりです。
- すべてのJavaオブジェクトには8バイトのオーバーヘッドがあります。
- Java配列には、追加の4バイトのオーバーヘッド(サイズの格納用)があります。
- リンクのサイズは4バイトです。
- すべてのオブジェクトのサイズは8バイトで調整されます。
- 多次元配列は、配列参照の配列です。
この知識で十分です。 したがって、チェーンの最後にfloat [2]配列があります。 サイズは2フロート(各4バイト)+ 12バイトのオーバーヘッド-20バイトです。 8〜24バイトに揃えられます。 合計で、
500 * 14 761-7 380 500個のヒープでそのような配列を作成しました。 合計で、
177,132,000バイトの重量が
あります。
次に、float配列が
あります[14761] []-他の配列への
14,761参照の配列。 このような各配列は、
14,761リンク(各4バイト)+ 12バイトのオーバーヘッド-59,056バイト(8で分割-位置合わせの必要なし)を占有します。 これらの配列は合計で500個あり、合計で
29,528,000バイトの重量が
あります。
最後に、作成した実際の配列があります-float [500] [] []-2次元配列への500参照の配列。
500 * 4 + 12 =
2 012 、さらに4アライメントバイト
-2 016バイトもかかります。
何が起こったのかを合計します:
177 132 000 + 29 528 000 + 2 016 =
206 662 016-メモリーアナライザーによって表示される数値のみ。
すぐに明らかな決定が浮かびました。配列の次元を昇順で並べることです。 float [2] [500] [14761]を作成しますが、アルゴリズムはこの問題を一切受けません。 この場合、どのサイズになりますか?
- 配列フロート[14761]: 14 761 * 4 + 12 = 59 056バイト、合計1,000のそのような配列、合計59 056 000バイト。
- 配列float [500] []: 500 * 4 + 12 = 2 012 、アライメント後-2 016 、合計2つのそのような配列で、合計4 032バイト。
- 配列float [2] [] []:アライメント後の2 * 4 + 12 = 20-24バイト。
合計で59,060,056バイト、0.03%未満のオーバーヘッド、約150メガバイトのメモリが節約されました。
ここからは経験則に従います。測定による配列の次元が少なくとも事前にわかっている場合は、測定値を昇順に並べる必要があります。 また、メモリアナライザーを使用することも忘れないでください。プログラムについて多くを学ぶことができます。