Попытка понять след ArrayList в JOLSample_16_AL_LL

Вот ссылка на рассматриваемый код - 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();
}

Когда я запускаю код как есть, я вижу следующее:

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)

Я не уверен, где 4952 байта для [Ljava.lang.Object; исходит из. Если я обновлю создание ArrayList и установлю начальный размер 1000, чтобы не было роста, я получаю следующее:

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)

Спасибо.

ОБНОВЛЕНИЕ

Я отключил CompressedOops (-XX:-UseCompressedOops). Вот новый результат:

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)

Таким образом, при отключении CompressedOops размеры ссылок увеличиваются до 8 байт. Для меня это имеет еще больший смысл, поскольку массив объектов содержит ссылки на 1000 целочисленных объектов.


person Jon    schedule 12.09.2016    source источник


Ответы (1)


ArrayList внутри поддерживается Object[] в качестве буфера, который растет по мере необходимости.

Массив объектов на самом деле является массивом ссылок на объекты. В вашем случае похоже, что каждая ссылка на объект составляет 4 байта, поэтому массив из них будет использовать 4 * length байт, а также некоторые накладные расходы, такие как длина массива и другие вещи.

Когда вы позволяете ArrayList увеличиваться естественным образом, любые неиспользуемые индексы в буферном массиве по умолчанию равны null, что по-прежнему использует 4 байта памяти на индекс.

ArrayList, который разрешает рост, вероятно, расширился до (4952 - 16) / 4 = ~1234 емкости.

В то время как ArrayList, который не требует расширения, имеет только емкость 1000.

person 4castle    schedule 12.09.2016
comment
Имеет смысл. Спасибо за быстрый ответ! - person Jon; 12.09.2016
comment
В 32-битной архитектуре ссылка на объект составляет 4 байта (32 бита), а в 64-битной архитектуре ссылка на объект составляет 8 байтов, но некоторые JVM могут сжиматься до 4 байтов. - person 4castle; 12.09.2016
comment
На моей машине работала 64-битная JVM, но ссылки на объекты отображались как 32-битные. Это одна из причин, по которой я был сбит с толку. Когда я отключаю CompressedOops (-XX:-UseCompressedOops), ссылки становятся 64-битными. Я добавил обновление к своему исходному вопросу, чтобы показать это. - person Jon; 13.09.2016
comment
@Jon Хорошо, мой комментарий был ответом на ваше обновление, просто для полноты картины. Об этом говорит и ссылка на 4 байта в моем ответе. - person 4castle; 13.09.2016