Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8281631

HashMap copy constructor and putAll can over-allocate table

XMLWordPrintable

    • b15
    • generic
    • generic
    • Verified

      ADDITIONAL SYSTEM INFORMATION :
      failed on all java 8, 11, and 17
      tested only on windows 10.

      A DESCRIPTION OF THE PROBLEM :
      sometimes HashMap.putAll would cause the hashmap.table be double length than should be.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      for jdk 8-:
      just run the tests I provided and see the results.
      for jdk 9+:
      make a break point before the System.out.println("a : " + getArrayLength(a));
      then see values of a.table.length, b.table.length, c.table.length, d.table.length using debugger tool.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      for jdk 8-:
      the output should be
      a : 16
      b : 16
      c : 16
      d : 16
      for jdk 9+:
      a.table.length = 16
      b.table.length = 16
      c.table.length = 16
      d.table.length = 16
      ACTUAL -
      for jdk 8-:
      the output should be
      a : 16
      b : 16
      c : 32
      d : 32
      for jdk 9+:
      a.table.length = 16
      b.table.length = 16
      c.table.length = 32
      d.table.length = 32

      ---------- BEGIN SOURCE ----------
      import java.lang.reflect.Array;
      import java.lang.reflect.Field;
      import java.util.HashMap;
      import java.util.Map;

      public class TestMap {

          public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
              HashMap<Object, Object> a = new HashMap<>();
              fill12(a);
              HashMap<Object, Object> b = new HashMap<>(12);
              fill12(b);
              HashMap<Object, Object> c = new HashMap<>(a);
              HashMap<Object, Object> d = new HashMap<>();
              d.putAll(a);
              System.out.println("a : " + getArrayLength(a));
              System.out.println("b : " + getArrayLength(b));
              System.out.println("c : " + getArrayLength(c));
              System.out.println("d : " + getArrayLength(d));
          }

          public static void fill12(Map<Object, Object> map) {
              for (int i = 0; i < 12; i++) {
                  map.put(i, i);
              }
          }

          public static int getArrayLength(Map<Object, Object> map) throws NoSuchFieldException, IllegalAccessException {
              Field field = HashMap.class.getDeclaredField("table");
              field.setAccessible(true);
              Object table = field.get(map);
              return Array.getLength(table);
          }

      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      change the original calculation from (int) (expected / 0.75F + 1) to (int) Math.ceil(expected / 0.75)

      FREQUENCY : always


            smarks Stuart Marks
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: