2

私は、学生 (私はこのコンテキストではティーチング アシスタントです) が独自のバージョンの単方向リンク リスト (SLL) を実装し、それを二重リンク リストの Java 標準ライブラリ実装と経験的に比較しなければならないという奇妙な状況に遭遇しました。

そして、それが奇妙なところです.複数の学生が、同じタイプの同じ数の要素を含む SLL と比較して、DLL プロファイルが約 0.5% 余分なスペース使用率であることに気付いているのを見てきました。データ構造の基本的な分析では、SLL にはノードごとに 2 つの参照 (次の要素への 1 つと含まれる値への 1 つ) があるのに対し、DLL には 3 つ (前の要素への追加の 1 つの参照) があることがわかります。つまり、ノードあたりのスペース使用量が 50% 増加します (含まれる値のサイズを無視します)。

含まれる値はほとんどが整数値オブジェクトなので、含まれる値のサイズはここではあまり重要ではないと思います。

この2 桁の違いの原因は何ですか? 「JVM/コレクションライブラリの最適化」がすべての違いをカバーできるかどうかは完全にはわかりません。そうでなければ、JVM/Java std lib の最適化の地獄にならなければなりません。

4

3 に答える 3

3

使用されるスペースは、32 ビット参照 (圧縮 oops) を持つ 64 ビット JVM の Oracle JVM/OpenJDK で同じである必要があります。

2 つの参照を持つノードの場合

header: 12 bytes
two references: 8 bytes
alignment padding: 4 bytes

デフォルトでは、すべてのオブジェクトが 8 バイトのオフセットで整列されるため、合計はノードあたり 24 バイトです。

3 つの参照を持つノードの場合

header: 12 bytes
three references: 12 bytes
alignment padding: 0 bytes

合計は再び 24 バイトです。

本当の問題は、なぜ違いが見られたのかということです。これは、不正確なメモリ アカウンティングが原因である可能性が最も高いです。

JVM は TLAB (Thread Local Allocation Buffer) を使用します。これにより、JVM 内のスレッドがメモリのチャンクを取得し、それらのチャンクから同時に割り当てることができます。欠点としては、共通の Eden スペースからどれだけのメモリが使用されているかしかわかりません。つまり、各チャンクがどれだけ使用されているかわかりません。

これを回避する簡単な方法は、TLAB をオフにすることです。これにより、バイト単位のメモリ アカウントが得られます (ただし、パフォーマンスが多少低下します)。

コマンド ラインでTLAB-XX:-UseTLABを無効にすると、割り当てられたすべてのオブジェクトのサイズが表示されます。

于 2015-02-25T08:54:23.847 に答える