0

容量は、オブジェクトを参照する値を保持する場合と保持しない場合がある ArrayList 内の要素または使用可能なスペースの数であることを理解しています。容量の概念についてもっと理解しようとしています。

だから私は3つの質問があります:

1) メモリの観点から容量が表すものを定義する良い方法は何ですか?

...ArrayList に割り当てられた (連続した?) メモリ?

...(ヒープ?)上のArrayListsのメモリフットプリント?

2) 上記が当てはまる場合、容量の変更には何らかのメモリ管理オーバーヘッドが必要ですか?

3) #2 がパフォーマンスの問題であった、または問題になる可能性のある例を誰かが持っていますか? 容量が継続的に調整されている多数の大きな ArrayLists を除いて?

4

4 に答える 4

3
  1. このクラスは配列に基づいているため、ArrayListと呼ばれます。容量はアレイのサイズであり、連続するヒープメモリのブロックが必要です。ただし、配列自体には、ヒープ上の個別のオブジェクトである要素への参照のみが含まれていることに注意してください。
  2. 容量を増やすには、新しい、より大きな配列を割り当て、古い配列から新しい配列にすべての参照をコピーする必要があります。その後、古い配列がガベージコレクションの対象になります。
  3. パフォーマンスが問題になる可能性がある主なケースを引用しました。実際には、要素オブジェクトは通常、リストよりもはるかに多くのメモリ(および場合によってはCPU時間)を消費するため、実際に問題になることはありません。
于 2011-03-23T20:31:02.770 に答える
2

ArrayListは次のように実装されます。

class ArrayList {
  private Object[] elements;
}

容量はそのアレイのサイズです。

ここで、容量が10で、11番目の要素を追加する場合、ArrayListはこれを実行します。

Object[] newElements = new Object[capacity * 1.5];
System.arraycopy(this.elements, newElements);
this.elements = newElements;

したがって、小さな容量から始めると、ArrayListは一連の配列を作成し、要素を追加し続けると、それらをコピーしてしまうことになりますが、これは良くありません。

一方、1,000,000の容量を指定し、ArrayListに3つの要素のみを追加する場合、これもやや悪いことです。

経験則:容量がわかっている場合は、それを指定します。わからないが上限がわかっている場合は、それを指定してください。よくわからない場合は、デフォルトを使用してください。

于 2011-03-23T20:30:33.520 に答える
1

容量はあなたが説明したとおりです-値の保存のためにArrayListに割り当てられた連続したメモリ。ArrayList はすべての値を配列に格納し、配列のサイズを自動的に変更します。これにより、サイズ変更時にメモリ管理のオーバーヘッドが発生します。

私の記憶が正しければ、Java は ArrayList のバッキング配列のサイズをサイズ N からサイズ 2N + 2 に増やします。これは、容量を超える要素を 1 つ追加しようとするとです。insertメソッド (または同様の方法) を使用して、容量の終わりを超えて特定の位置に挿入すると、どのサイズまで増加するか、またはこれが許可されるかどうかさえわかりません。

これがどのように機能するかを考えるのに役立つ例を次に示します。s の間の各スペースを|バッキング配列のセルとして描写します。

| | |

サイズ = 0 (要素を含まない)、容量 = 2 (2 つの要素を含むことができる)。

|1| |

サイズ = 1 (要素を 1 つ含む)、容量 = 2 (要素を 2 つ含むことができる)。

|1|2|

サイズ = 2、容量 = 2。別の要素を追加:

|1|2|3| | | |

サイズが 1 増加し、容量が 6 (2 * 2 + 2) に増加しました。JVM は適切な場所を検索する必要があるため、大きな連続したメモリ領域を割り当てるには少し作業が必要になる可能性があるため (多くの小さなメモリ断片を割り当てる LinkedList とは対照的に)、大きな配列ではコストがかかる可能性があります。 OSにメモリの追加を要求します。また、大量の値をある場所から別の場所にコピーすることもコストがかかります。これは、そのような領域が見つかった場合に行われます。

私の経験則は次のとおりです。必要な容量がわかっている場合は、ArrayList を使用します。これは、割り当てが 1 つしかなく、アクセスが非常に高速であるためです。必要な容量がわからない場合は、LinkedList を使用してください。新しい値を追加するのに必要な作業量は常に同じであり、コピーは必要ありません。

于 2011-03-23T20:33:28.577 に答える
0

1) メモリの観点から容量が表すものを定義する良い方法は何ですか?

...ArrayList に割り当てられた (連続した?) メモリ?

はい、ArrayList は配列によってバックアップされ、内部配列サイズを表します。

...(ヒープ?)上のArrayListsのメモリフットプリント?

はい、配列容量が大きいほど、arraylist が使用するフットプリントが大きくなります。

2) 上記が当てはまる場合、容量の変更には何らかのメモリ管理オーバーヘッドが必要ですか?

です。リストが十分に大きくなると、より大きな配列が割り当てられ、内容がコピーされます。以前の配列は破棄され、ガベージ コレクションのマークが付けられる場合があります。

3) #2 がパフォーマンスの問題であった、または問題になる可能性のある例を誰かが持っていますか? 容量が継続的に調整されている多数の大きな ArrayLists を除いて?

はい、初期容量 1 (たとえば) の ArrayList を作成し、リストがそれを超えて大きくなる場合。格納する要素の数が事前にわかっている場合は、そのサイズの初期容量を要求することをお勧めします。

ただし、配列のコピーは非常に頻繁に発生する可能性がありますが、Java の初期段階から最適化されており、懸念すべきではありませんが、これは優先順位のリストでは低くする必要があると思います。適切なアルゴリズムを選択する方がよいと思います。覚えておいてください:時期尚早の最適化は諸悪の根源です

関連項目: ArrayList よりも LinkedList を使用する場合

于 2011-03-23T20:45:34.407 に答える