[英]Is it better to set size of a Java Collection in constructor?
如果我知道當時的大小,最好將Collection
的大小傳遞給Collection
構造函數嗎? 在擴展Collection
和分配/重新分配方面的節省效果是否顯着?
如果我知道Collection
最小大小但不知道上限,該怎么辦。 至少以最小的尺寸創建它仍然值得嗎?
不同的集合對此有不同的性能影響,對於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
因此,即使大小不同,您也可以看到比率保持不變。
這幾乎是最壞的測試,但是一次填充一個元素一個數組很常見,您會發現速度大約相差2倍。
所有集合都是自動擴展的。 不知道邊界不會影響其功能(直到遇到其他問題,例如使用所有可用內存等),但是可能會影響其性能。
有一些收藏。 最值得注意的是ArrayList,因為要復制整個基礎數組,所以自動擴展的成本很高。 數組列表的默認大小為10,每次達到最大值時,其大小都會增加一倍。 因此,假設您知道您的arraylist將包含110個對象,但不指定其大小,則將發生以下復制
復制10-> 20
復制20-> 40
復制40-> 80
復制80-> 160
通過預先告訴arraylist它包含110個項目,您可以跳過這些副本。
即使您錯了也沒關系。 集合仍將自動展開,並且您仍將避免某些副本。 降低性能的唯一方法是,如果您的猜測太大了:這將導致分配給集合的內存過多
好,這是我的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
如果增加初始大小,則可以使您的心臟感到溫暖,但客觀地說,客戶不太可能注意到差異。
在少數情況下,大小是眾所周知的(例如,當將已知數量的元素填充到新集合中時),出於性能原因可以進行設置。
通常,最好省略它,而改用默認構造函數,這樣可以使代碼更簡單和更好理解。
對於基於數組的集合,重新調整大小是一項非常昂貴的操作。 這就是為什么為ArrayList
傳遞准確大小是一個好主意的原因。
如果將大小設置為最小大小( MIN
),然后將MIN
+1個元素添加到集合中,則需要重新調整大小。 ArrayList()
調用ArrayList(10)
因此如果MIN
足夠大,那么您將獲得一些好處。 但是最好的方法是使用期望的集合大小創建ArrayList
。
但是可能您更喜歡LinkedList,因為它沒有添加元素的任何開銷(盡管list.get(i)
開銷為O(i))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.