javaarraylistjvmjol

Trying to understand the footprint of ArrayList in JOLSample_16_AL_LL


Here is a link to the code in question - http://hg.openjdk.java.net/code-tools/jol/file/07087260ce41/jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_16_AL_LL.java

public static void main(String[] args) throws Exception {
    out.println(VM.current().details());

    List<Integer> al = new ArrayList<Integer>();
    List<Integer> ll = new LinkedList<Integer>();

    for (int i = 0; i < 1000; i++) {
        Integer io = i; // box once
        al.add(io);
        ll.add(io);
    }

    PrintWriter pw = new PrintWriter(out);
    pw.println(GraphLayout.parseInstance(al).toFootprint());
    pw.println(GraphLayout.parseInstance(ll).toFootprint());
    pw.println(GraphLayout.parseInstance(al, ll).toFootprint());
    pw.close();
}

When I run the code as is I see the following:

java.util.ArrayList@5f205aad footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1      4952      4952   [Ljava.lang.Object;
      1000        16     16000   java.lang.Integer
         1        24        24   java.util.ArrayList
      1002               20976   (total)

I am unsure where the 4952 bytes for [Ljava.lang.Object; is coming from. If I update the ArrayList creation and set a initial size to 1000 so that there is no growing I get the following:

java.util.ArrayList@5f205aad footprint:
 COUNT       AVG       SUM   DESCRIPTION
     1      4016      4016   [Ljava.lang.Object;
  1000        16     16000   java.lang.Integer
     1        24        24   java.util.ArrayList
  1002               20040   (total)

Thanks.

UPDATE

I turned off CompressedOops (-XX:-UseCompressedOops). Here is the new result:

java.util.ArrayList@1996cd68d footprint:
 COUNT       AVG       SUM   DESCRIPTION
     1      8024      8024   [Ljava.lang.Object;
  1000        24     24000   java.lang.Integer
     1        40        40   java.util.ArrayList
  1002               32064   (total)

So when disabling CompressedOops the reference sizes increase to 8 bytes. To me that makes even more sense that the Object array holds the references to the 1000 Integer Objects.


Solution

  • ArrayList internally is backed by an Object[] as a buffer, which grows as needed.

    An array of objects is actually an array of object references. In your case, it looks like each object reference is 4 bytes, so an array of them would use 4 * length bytes, plus some overhead such as the length of the array and other stuff.

    When you allow the ArrayList to grow naturally, any unused indexes in the buffer array default to null, which still uses 4 bytes of memory per index.

    The ArrayList that allows growth has probably expanded to (4952 - 16) / 4 = ~1234 capacity.

    While the ArrayList that doesn't require growth only has 1000 capacity.