天天看點

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

相信大家都知道集合存在擴容機制,是以使用時進行初始化容量進而達到減少其擴容操作,來實作提高性能的目的。

但是集合初始化容量後就一定能送出效率碼?答案當然是否定的,不合理的使用初始化容量反而會降低性能,因為記憶體的不合理申請,必然會影響GC過程,都知道尤其FULL GC一定要避而遠之。

研究開始:

先看示例:

下面是一段簡單的循環體代碼,在循環内使用向ArrayList集合添加資料。

public static void outsideLoop() {
    List<String> list = new ArrayList<>();
    int i = 0;
    while (i++ < 5000000){
      list.add("String 0");
    }
  }
           

執行效率:55ms

第一步實踐:初始化容量為 5000000

public static void outsideLoop() {
    List<String> list = new ArrayList<>(5000000);
    int i = 0;
    while (i++ < 5000000){
      list.add("String 0");
    }
  }
           

執行效率:13ms

哇哦真棒!這效率提升的杠杠的。

第二步實踐:初始化容量為 10000

public static void outsideLoop() {
    List<String> list = new ArrayList<>(10000);
    int i = 0;
    while (i++ < 5000000){
      list.add("String 0");
    }
  }
           

執行效率:59ms !!

我擦,不對啊,雖然初始化容量小于list大小,雖然不能避免list擴容,但是明明減少了list擴容的次數啊,為什麼相對于沒有設定初始化容量時,性能還要低呢?

接下來我在使用不同的容量給大家看下效率:

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

 可以看到不同容量初始化性能有着這樣的一個趨向,那這樣是為什麼麼?

那我這邊先說下結論,這個可能需要點jvm知識基礎:

當程式執行到:

List<String> list = new ArrayList<>() 時,會建立list對象,并向堆中申請一塊記憶體空間,此時該對象是劃分在年輕代

當對象建立越來越多時,YGC就會越來越頻繁。是以如果list對象越大且還不是“大對象”時,占用年輕代空間就多。

那這也就是為什麼,不設定容量效率 > 容量為10000 - 900000

如果設定的容量很大,當超過臨界值(大對象)時就會直接配置設定到老年代,

此時年輕代壓力就減少了。這就是為什麼當容量大于1000000時 效率降低了。 

但是如果對象過多時,因為大對象list對老年代的占用,是以觸發full GC機率也高了,是以容量設定過大也會降低效率,甚至産生OOM。

下面簡單發一下驗證過程:

不設定容量時:

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

100000容量:

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

900000容量:

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

 1000000容量:

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

5000000容量:

JAVA程式性能優化研究 - 集合初始化容量一定能提高效率 ?

 通過驗證好像正如我們所推測的:

當容量小于1000000時,都産生了YGC,而大于1000000時沒有産生YGC。

當然我也試了下list中添加其他不同大小的對象,可以确定的是并不是容量設定為size時就一定會提高效率,有時候還會降低效率,至于其原因以上分析都為個人了解和分析結果。是以結論如下:

1、通過初始化集合容量來提高效率,需要合理的去設定容量大小,需要綜合考慮空間和記憶體配置設定問題,并不是一定使用size就能提高效率。

2、以上分析過程為個人了解,如有不對或者其他分析,望留言指出!