1

その時点でサイズがわかっている場合は、コンストラクターCollectionにサイズを渡す方が良いですか? 拡張と割り当て/再割り当てCollectionに関する節約効果は顕著ですか?Collection

Collectionの最小サイズがわかっているが、上限がわからない場合はどうなりますか。少なくとも最小限のサイズで作成する価値はありますか?

4

5 に答える 5

6

コレクションが異なれば、パフォーマンスへの影響も異なります。ArrayList の場合、節約は非常に顕著です。

import java.util.*;
public class Main{
public static void main(String[] args){
  List<Integer> numbers = new ArrayList<Integer>(5);
  int max = 1000000;
  // Warmup
  for (int i=0;i<max;i++) {
    numbers.add(i);
  }

  long start = System.currentTimeMillis();
  numbers = new ArrayList<Integer>(max);
  for (int i=0;i<max;i++) {
    numbers.add(i);
  }
  System.out.println("Preall: "+(System.currentTimeMillis()-start));

  start = System.currentTimeMillis();
  numbers = new ArrayList<Integer>(5);
  for (int i=0;i<max;i++) {
    numbers.add(i);
  }
  System.out.println("Resizing: "+(System.currentTimeMillis()-start));

}
}

結果:

Preall: 26
Resizing: 58

max を 10000000 の値の 10 倍に設定して実行すると、次のようになります。

Preall: 510
Resizing: 935

したがって、サイズが異なっていても比率がほぼ同じであることがわかります。

これはほとんど最悪のケースのテストですが、配列を一度に 1 つの要素で埋めることは非常に一般的であり、約 2 倍の速度の違いがあることがわかります。

于 2014-01-15T13:38:32.757 に答える
5

OK、これが私のjmhコードです:

@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(3)
public class Comparison
{
  static final int size = 1_000;
  @GenerateMicroBenchmark
  public List<?> testSpecifiedSize() {
    final ArrayList<Integer> l = new ArrayList(size);
    for (int i = 0; i < size; i++) l.add(1);
    return l;
  }

  @GenerateMicroBenchmark
  public List<?> testDefaultSize() {
    final ArrayList<Integer> l = new ArrayList();
    for (int i = 0; i < size; i++) l.add(1);
    return l;
  }
}

の結果size = 10_000:

Benchmark             Mode Thr    Cnt  Sec         Mean   Mean error    Units
testDefaultSize       avgt   1      9    1       80.770        2.095  usec/op
testSpecifiedSize     avgt   1      9    1       50.060        1.078  usec/op

の結果size = 1_000:

Benchmark             Mode Thr    Cnt  Sec         Mean   Mean error    Units
testDefaultSize       avgt   1      9    1        6.208        0.131  usec/op
testSpecifiedSize     avgt   1      9    1        4.900        0.078  usec/op

私の解釈:

  • プレサイジングには、デフォルトのサイズよりも優位性があります。
  • エッジはそれほど壮観ではありません。
  • リストに追加するタスクに費やされる絶対時間は、まったく重要ではありません。

私の結論:

心の周りが暖かく感じる場合は、最初のサイズを追加しますが、客観的に言えば、顧客が違いに気付く可能性はほとんどありません.

于 2014-01-15T14:09:52.973 に答える
4

すべてのコレクションは自動拡張されます。境界がわからなくても機能に影響はありません (使用可能なすべてのメモリを使用するなど、他の問題が発生するまで) が、パフォーマンスに影響を与える可能性があります。

いくつかのコレクションで。最も顕著なのは ArrayList で、基になる配列全体がコピーされるため、自動展開はコストがかかります。配列リストのデフォルト サイズは 10 で、最大値に達するたびにサイズが 2 倍になります。したがって、arraylist に 110 個のオブジェクトが含まれることがわかっているが、サイズを指定しないと、次のコピーが発生します。

コピー 10 --> 20
コピー 20 --> 40
コピー 40 --> 80
コピー 80 --> 160

arraylist に 110 個のアイテムが含まれていることを前もって伝えることで、これらのコピーをスキップします。

経験に基づいた推測は、何もないよりはましです

間違っていても問題ありません。コレクションは引き続き自動拡張され、一部のコピーは回避されます。パフォーマンスを低下させる唯一の方法は、推測が大きすぎる場合です。これにより、コレクションに割り当てられるメモリが多すぎます。

于 2014-01-15T13:42:58.717 に答える
0

サイズがよくわかっているまれなケース (たとえば、既知の数の要素を新しいコレクションに入れる場合) では、パフォーマンス上の理由で設定されることがあります。

ほとんどの場合、それを省略して代わりにデフォルトのコンストラクターを使用することをお勧めします。これにより、コードがよりシンプルで理解しやすくなります。

于 2014-01-15T13:45:22.833 に答える
0

配列ベースのコレクションの場合、サイズ変更は非常にコストのかかる操作です。そのため、正確なサイズを渡すことをArrayListお勧めします。

サイズを最小サイズ ( ) に設定し、コレクションに +1 要素MINを追加すると、サイズが変更されます。十分に大きい場合は、いくつかの利点があります。しかし、最善の方法は、予想されるコレクション サイズで作成することです。MINArrayList()ArrayList(10)MINArrayList

ただし、要素を追加するためのコストがないため、LinkedList を好む可能性があります (ただしlist.get(i)、O(i) コストはかかります)。

于 2014-01-15T13:54:56.413 に答える