Why is Arrays.fill() not used in HashMap.clear() anymore?

后端 未结 5 504
太阳男子
太阳男子 2021-01-30 16:02

I noticed something strange in the implementation of HashMap.clear(). This is how it looked in OpenJDK 7u40:

public void clear() {
    modCount++;
          


        
5条回答
  •  佛祖请我去吃肉
    2021-01-30 16:36

    Because it's much faster!

    I ran some thorough benchmarking tests on cut down versions of the two methods:

    void jdk7clear() {
        Arrays.fill(table, null);
    }
    
    void jdk8clear() {
        Object[] tab;
        if ((tab = table) != null) {
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }
    

    operating on arrays of various sizes containing random values. Here are the (typical) results:

    Map size |  JDK 7 (sd)|  JDK 8 (sd)| JDK 8 vs 7
           16|   2267 (36)|   1521 (22)| 67%
           64|   3781 (63)|   1434 ( 8)| 38%
          256|   3092 (72)|   1620 (24)| 52%
         1024|   4009 (38)|   2182 (19)| 54%
         4096|   8622 (11)|   4732 (26)| 55%
        16384|  27478 ( 7)|  12186 ( 8)| 44%
        65536| 104587 ( 9)|  46158 ( 6)| 44%
       262144| 445302 ( 7)| 183970 ( 8)| 41%
    

    And here are the results when operating over an array filled with nulls (so garbage collection issues are eradicated):

    Map size |  JDK 7 (sd)|  JDK 8 (sd)| JDK 8 vs 7
           16|     75 (15)|     65 (10)|  87%
           64|    116 (34)|     90 (15)|  78%
          256|    246 (36)|    191 (20)|  78%
         1024|    751 (40)|    562 (20)|  75%
         4096|   2857 (44)|   2105 (21)|  74%
        16384|  13086 (51)|   8837 (19)|  68%
        65536|  52940 (53)|  36080 (16)|  68%
       262144| 225727 (48)| 155981 (12)|  69%
    

    The numbers are in nanoseconds, (sd) is 1 standard deviation expressed as a percentage of the result (fyi, a "normally distributed" population has an SD of 68), vs is the JDK 8 timing relative to JDK 7.

    It is interesting that not only is it significantly faster, but the deviation is also slightly narrower, which means that the JDK 8 implementation gives slightly more consistent performance.

    The tests were run on jdk 1.8.0_45 over a large (millions) number of times on arrays populated with random Integer objects. To remove out-lying numbers, on each set of results the fastest and slowest 3% of timings were discarded. Garbage collection was requested and the thread yielded and slept just prior to running each invocation of the method. JVM warm up was done on the first 20% of work and those results were discarded.

提交回复
热议问题