2

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.

Jon
  • 237
  • 3
  • 12

1 Answers1

3

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.

Community
  • 1
  • 1
4castle
  • 32,613
  • 11
  • 69
  • 106
  • Makes sense. Thanks for the quick response! – Jon Sep 12 '16 at 03:38
  • 1
    On a 32-bit architecture an object reference is 4 bytes (32-bits), and on a 64-bit architecture an object reference is 8 bytes, but some JVMs can compress to 4 bytes. – 4castle Sep 12 '16 at 14:32
  • My machine was running a 64-bit JVM, but showing object references as 32-bits. That is part of the reason why I was confused. When I turn off CompressedOops (-XX:-UseCompressedOops) the references went to 64-bits. I added an update to my original question to show this. – Jon Sep 13 '16 at 01:34
  • @Jon Right, my comment was in response to your update, just for completeness. The link on "4 bytes" in my answer talks about it also. – 4castle Sep 13 '16 at 01:52