5

Java の int の配列は、32 ビット値のブロックとしてメモリに格納されます。整数オブジェクトの配列はどのように格納されますか? すなわち

int[] vs. Integer[]

Integer 配列の各要素は Integer オブジェクトへの参照であり、Integer オブジェクトには他のオブジェクトと同様にオブジェクト ストレージのオーバーヘッドがあると思います。

ただし、整数が不変であり、int の配列のように格納されることを考えると、JVM がフードの下で魔法のような賢さを発揮することを願っています。

私の希望はひどく素朴ですか?パフォーマンスの最後の一滴までが重要なアプリケーションで、Integer 配列は int 配列よりもはるかに遅いですか?

4

5 に答える 5

12

私が知っている VM は、次の理由から、int[] 配列のような Integer[] 配列を格納しません。

  1. 配列にnull Integer オブジェクトが存在する可能性があり、int 配列でこれを示すためのビットが残っていません。ただし、VM は、配列スロットごとにこの 1 ビットの情報を隠しビット配列に格納できます。
  2. 整数配列の要素で同期できます。これは、配列スロットごとに監視オブジェクトを格納する必要があるため、最初のポイントとして克服するのがはるかに困難です。
  3. Integer[] の要素は同一性のために比較できます。たとえば、newを介して値 1 を持つ 2 つの Integer オブジェクトを作成し、それらを異なる配列スロットに格納し、後でそれらを取得して == を介して比較することができます。これは false につながる必要があるため、この情報をどこかに保存する必要があります。または、Integer オブジェクトの 1 つへの参照をどこかに保持し、これを比較に使用して、== 比較の 1 つが false で 1 つが true であることを確認する必要があります。これは、オブジェクト ID の概念全体が、最適化されたInteger 配列で処理するのが非常に難しいことを意味します。
  4. Integer[] を Object[] などにキャストし、Object[] だけを期待するメソッドに渡すことができます。これは、Object[] を処理するすべてのコードが、特別な Integer[] オブジェクトも処理できるようにする必要があることを意味し、速度とサイズが大きくなります。

これらすべてを考慮すると、特別な Integer[] を作成して、素朴な実装と比較してスペースを節約することはおそらく可能ですが、追加の複雑さは他の多くのコードに影響を与える可能性があり、最終的に遅くなります。

int[] の代わりに Integer[] を使用することによるオーバーヘッドは、スペースと時間の面で静かに大きくなる可能性があります。典型的な 32 ビット VM では、Integer オブジェクトは 16 バイト (オブジェクト ヘッダーに 8 バイト、ペイロードに 4 バイト、アライメントに 4 バイト) を消費しますが、Integer[] は int[] と同じスペースを使用します。64 ビット VM (常にそうとは限りませんが、64 ビット ポインターを使用) では、Integer オブジェクトは 24 バイト (ヘッダーに 16、ペイロードに 4、アラインメントに 4) を消費します。さらに、Integer[] のスロットは、int[] のように 4 ではなく 8 バイトを使用します。これは、スロットごとに16 から 28バイトのオーバーヘッドが予想されることを意味します。これは、プレーンな int 配列と比較して4 から 7 倍です。

主に次の 2 つの理由から、パフォーマンスのオーバーヘッドも大きくなる可能性があります。

  1. より多くのメモリを使用するため、メモリ サブシステムにかかる負荷が大きくなり、Integer[] の場合にキャッシュ ミスが発生する可能性が高くなります。たとえば、int[] の内容を線形にトラバースすると、必要なときにほとんどのエントリがキャッシュに取り込まれます (レイアウトも線形であるため)。しかし、Integer 配列の場合、Integer オブジェクト自体がヒープ内にランダムに散在している可能性があり、キャッシュが次のメモリ参照がどこを指すかを推測するのが難しくなります。
  2. ガベージ コレクションは、追加のメモリを使用し、各 Integer オブジェクトを個別にスキャンして移動する必要があるため、より多くの作業を行う必要があります。一方、int[] の場合、それは 1 つのオブジェクトであり、オブジェクトの内容はそうではありません。スキャンする必要があります (他のオブジェクトへの参照は含まれません)。

要約すると、パフォーマンス クリティカルな作業で int[] を使用すると、現在の VM で Integer 配列を使用するよりもはるかに高速かつメモリ効率が高くなり、これが近い将来大きく変わる可能性はほとんどありません。

于 2008-09-17T07:12:47.117 に答える
3

John Roseは、この問題を修正するために JVM のfixnumsに取り組んでいます。

于 2008-09-17T05:15:38.600 に答える
1

あなたの希望はひどくナイーブだと思います。具体的には、整数は null になる可能性があるが、int はできないという問題に対処する必要があります。それだけで、オブジェクト ポインターを格納するのに十分な理由になります。

つまり、実際のオブジェクト ポインターは、特に整数の選択サブセットの場合、不変の int インスタンスになります。

于 2008-09-16T20:25:41.883 に答える
0

Integerがnullになる可能性があるのに対し、intはnullにならない理由は、Integerが本格的なJavaオブジェクトであり、を含むすべてのオーバーヘッドがあるためです。あなたが書くことができるので、これには価値があります

Integer foo = new Integer();
foo = null; 

これは、fooに値があると言うのに適していますが、まだ値がありません。

もう1つの違いは、intオーバーフロー計算を実行しないことです。例えば、

int bar = Integer.MAX_VALUE;
bar++;

陽気にバーをインクリメントし、非常に負の数になります。これは、おそらく最初に意図したものではありません。

foo = Integer.MAX_VALUE;
foo++;

不平を言うでしょう、それは私がより良い行動だと思います。

最後のポイントは、JavaオブジェクトであるIntegerが、オブジェクトのスペースオーバーヘッドを伴うことです。他の誰かがここでチャイムを鳴らす必要があるかもしれないと思いますが、すべてのオブジェクトがオーバーヘッドのために12バイトを消費し、次にデータストレージ自体のためのスペースを消費すると思います。あなたがパフォーマンスとスペースを求めているなら、整数が正しい解決策であるかどうか疑問に思います。

于 2008-09-16T20:35:16.637 に答える
0

それほど遅くはありませんが、Integer[] はエントリとして「null」を受け入れる必要があり、int[] はその必要がないため、Integer[] がint[]。

したがって、パフォーマンスの最後の一滴までが重要な場合、ユーザー int[]

于 2008-09-16T20:26:18.607 に答える