Java がパディングを使用していることは知っています。オブジェクトは 8 バイトの倍数でなければなりません。しかし、私はそれの目的を見ていません。それは何のために使用されますか?その主な目的は何ですか?
3 に答える
その目的はアラインメントです。これにより、スペースを犠牲にしてより高速なメモリアクセスが可能になります。データが整列されていない場合、プロセッサはメモリをロードした後、データにアクセスするためにいくつかのシフトを行う必要があります。
さらに、ガベージ コレクションは、最小アロケーション ユニットのサイズが大きいほど単純化 (および高速化) されます。
Java に 8 バイトの要件があるとは考えにくい (64 ビット システムを除く) が、Java が作成されたときは 32 ビット アーキテクチャが標準であったため、Java 標準で 4 バイト アラインメントが必要になる可能性があります。
受け入れられた答えは憶測です (ただし、部分的には正しいです)。これが本当の答えです。
まず、@U2EF1 の功績によると、8 バイト境界の利点の 1 つは、ほとんどのプロセッサで 8 バイトが最適なアクセスであることです。しかし、それ以上の決断がありました。
32 ビットの参照がある場合は、最大 2^32 または 4 GB のメモリをアドレス指定できます (実際には、3.5 GB ほど少なくなります)。64 ビットの参照がある場合は、テラバイトのメモリである 2^64 をアドレス指定できます。ただし、64 ビットの参照では、すべてが遅くなり、より多くのスペースが必要になる傾向があります。これは、64 ビットを処理する 32 ビット プロセッサのオーバーヘッドが原因であり、すべてのプロセッサで、スペースが少なくなりガベージ コレクションが増えるため、GC サイクルが増えます。
そのため、作成者は妥協点を取り、35 ビット参照を決定しました。これにより、最大 2^35 または 32 GB のメモリが可能になり、占有スペースが少なくなるため、32 ビット参照と同じパフォーマンス上の利点が得られます。これは、32 ビット参照を取得し、読み取り時に左に 3 ビットシフトし、参照を格納するときに右に 3 ビットシフトすることによって行われます。つまり、すべてのオブジェクトが 2^3 境界 (8 バイト) に配置されている必要があります。これらは、圧縮された通常のオブジェクト ポインターまたは圧縮された oops と呼ばれます。
64 GB のメモリにアクセスするための 36 ビット参照ではないのはなぜですか? まあ、それはトレードオフでした。16 バイトのアラインメントには多くの無駄なスペースが必要であり、私の知る限り、8 バイトのアラインメントとは対照的に、16 バイトのアラインメントによる速度の利点はほとんどのプロセッサで得られません。
最大メモリが 4 GB を超えるように設定されていない限り、JVM はわざわざ圧縮 oops を使用しないことに注意してください。これはデフォルトでは設定されていません。-XX:+UsedCompressedOops
フラグを使用して実際に有効にすることができます。
これは 32 ビット VM の時代にさかのぼり、64 ビット システムで追加の使用可能なメモリを提供するものでした。私の知る限り、64 ビット VM には制限がありません。
出典: Java パフォーマンス: 決定版ガイド、第 8 章
最近のほとんどのプロセッサのワード サイズは 8 ビットの倍数 (16 ビット、32 ビット、64 ビット) であるため、Java のデータ型のサイズは (バイトではなく) 8ビットの倍数です。このようにして、オブジェクト内のフィールドを 1 つまたは複数の単語に収まるように (「整列」) し、スペースをできるだけ無駄にしないようにして、基になるプロセッサの命令を利用して単語サイズのデータを操作することができます。