2013-01-14 78 views
-6

考慮以下兩個代碼示例。所有基準測試均在容器外部進行,用於計算採樣執行時間的平均值。在運行Windows 7和JDK 1.6的機器上,我看到示例2中的平均執行時間比示例1慢了近1000倍。我可以推測的唯一解釋是編譯器正在優化LinkedList使用的一些代碼,損害了其他一切。有人能幫助我理解這一點嗎?Java JIT編譯器是否犧牲性能來支持集合?

例1:使用數組

public class TimingTest 
{ 

    static long startNanos, endNanos; 
    static long[] samples = new long[1000]; 


    public static void main(String[] args) 
    { 
    for (int a = 0; a < 100; a++) 
    { 
     for (int numRuns = 0; numRuns < 1000; numRuns++) 
     { 
      startNanos = System.nanoTime(); 
      long sum = 0; 
      for (long i = 1; i <= 500000; i++) 
      { 
       sum += i % 13; 
      } 
      endNanos = System.nanoTime() - startNanos; 
      samples[numRuns] =(endNanos); 
     } 
     long avgPrim = 0L; 
     for (long sample : samples) 
     { 
      avgPrim += sample; 
     } 
     System.out.println("Avg: " + (avgPrim/samples.length)); 
     } 
    } 
} 

示例2:使用一個LinkedList

public class TimingTest 
{ 

    static long startNanos, endNanos; 
    static List<Long> samples = new LinkedList<Long>(); 

    public static void main(String[] args) 
    { 
     for (int a = 0; a < 100; a++) 
     { 
      for (int numRuns = 0; numRuns < 1000; numRuns++) 
      { 
       startNanos = System.nanoTime(); 
       long sum = 0; 
       int index = 0; 
       for (long i = 1; i <= 500000; i++) 
       { 
        sum += i % 13; 
       } 
       endNanos = System.nanoTime() - startNanos; 
       samples.add(endNanos); 
      } 
      long avgPrim = 0L; 
      for (long sample : samples) 
      { 
       avgPrim += sample; 
      } 
      System.out.println("Avg: " + (avgPrim/samples.size())); 
     } 
    } 
} 
+5

鏈接列表的性能特徵比數組的性能更差,但沒有太大的意義。 – vemv

+1

LinkedList沒有被基準測試! LinkedList僅存儲基準測試結果。 – user1975105

+0

@vemv這是一個不完整和誤導性的分析。鏈表具有比數組更好的性能特徵。另外,在第二個例子中,總結代碼的執行時間較慢,這個問題很明顯。 –

回答

3

東西是非常錯誤的位置:當我運行數組版本,我得到的20000的平均執行時間納秒。我的2 GHz CPU在那個時候執行500000循環迭代是完全不可能的,因爲那意味着平均循環迭代需要20000/500000 = 0.04 ns或0.08 cpu cpu週期...

主要原因在您的時間邏輯的錯誤:在陣列版本,你的每定時做

int index = 0; 

,因此

samples[index++] =(endNanos); 

將始終分配給第一個數組元素,讓所有的人在他們的默認值0.因此,當你取數組的平均值時,你得到1/1000的最後一個樣本,而不是所有樣本的平均值。

事實上,如果您將循環索引的聲明移到循環之外,則兩個變體之間沒有顯着差異報告。

0

這是你的代碼真正運行時(改名類的清晰度,並削減在每個到a < 1循環外面時間的緣故):

$ for f in *.class 
do 
    class=$(echo $f | sed 's`\(.*\)\.class`\1`') 
    echo Running $class 
    java $class 
done 
Running OriginalArrayTimingTest 
Avg: 18528 
Running UpdatedArrayTimingTest 
Avg: 41111273 
Running LinkedListTimingTest 
Avg: 41340483 

顯然,你最初的擔憂是由輸入錯誤造成@ meriton指出,你糾正你的問題。我們可以看到,對於您的測試用例,數組和LinkedList的行爲幾乎完全相同。一般來說,LinkedList上的插入速度非常快。既然你用權威的修改更新了你的問題,但沒有更新你的說法,即前者比後者快得多,它不再清楚你要問什麼;但是我希望你現在可以看到,在這種情況下,兩個數據結構的行爲都是相似的。