Сравнение потребления памяти у разных структур хранения данных

Original author: Peter Lawrey
  • Translation
Различные структуры в Java потребляют разное количество памяти. Поэтому для нас очень важен выбор наиболее эффективного метода хранения данных.

Какая будет разница по потреблению памяти между конструкциями `new int[1024]` и `new Integer[1024]`?

int[] ints = new int[1024];
for (int i = 0; i < ints.length; i++) ints[i] = i;

Integer[] ints = new Integer[1024];
for (int i = 0; i < ints.length; i++) ints[i] = i;


Примечание: 1/8 часть значений типа Integer будут закешированы и не скушают лишнюю память. Все значения типов Boolean и Byte тоже будут закешированы.

Структура JVM 32-bit(размер в байтах) JVM 64-bit(размер в байтах)
new BitSet(1024) 168 168
new boolean[1024] 1040 1040
new Boolean[1024] 4112 4112
new ArrayList<Boolean>(1024) 4136 4136
new LinkedList<Boolean>() with 1024 24624 24624
new byte[1024] 1040 1040
new Byte[1024] 4112 4112
new ArrayList<Byte>(1024) 4136 4136
new LinkedList<Byte>() with 1024 24624 24624
new char[1024] 2064 2064
new Character[1024] 18448 18448
new short[1024] 2064 2064
new Short[1024] 18448 18448
new ArrayList<Character/Short>(1024) 18472 18472
new LinkedList<Character/Short>() with 1024 38960 38960
new int[1024] 4112 4112
new Integer[1024] 18448 18448
new float[1024] 4112 4112
new Float[1024] 20496 20496
new ArrayList<Integer/Float>(1024) 18472 18472
new LinkedList<Integer/Float>() with 1024 38960 38960
new long[1024] 8208 8208
new Long[1024] 18448 25616
new double[1024] 8208 8208
new Double[1024] 20496 28688
new ArrayList<Long/Double>(1024) 18472 25640
new LinkedList<Long/Double>() with 1024 38960 46128
new String[1024] 52464 61456
new ArrayList<String>(1024) 52488 61480
new LinkedList<String>() with 1024 72976 81968


Полный код доступен здесь

З.Ы. Предположительно все это должен знать любой JAVA разработчик, но если кто-то не знает, то улыбаемся и машем читаем и запоминаем :)
Share post

Comments 43

    +1
    Какая будет разница по потреблению памяти между конструкциями `new int[1024]` и `new Integer[1024]`?
    Сильно зависит от платформы, версии Java и ключей JVM.
    Если int[1024] всегда занимает около 4K, то объем Integer[1024] может варьироваться от тех же 4K
    (при -XX:+UseCompressedOops -XX:+AggressiveOpts) до 28K (при -XX:-UseCompressedOops).
      0
      В данном случае все тестирование происходило без всяких ключей и на Java 1.6
        0
        И да. Исходники именно для того присутствуют, чтобы вы могли на своей конфигурации(архитектура/версия жавы/ключи) запустить и посмотреть.
      +1
      Спасибо. Для меня очень полезная информация.
        +1
        Вкратце для людей несведущих написали бы почему так.
          +2
          int — скалярный тип
          Integer — класс.
            +1
            А почему new String[1024] занимает больше памяти, чем new Integer[1024]?
            И то и другое объекты, а массивы содержат только ссылки на объекты, разве нет?
              +1
              Integer хранит число в поле int, а String — как массив char-ов + дополнительные поля:

              private final char value[];

              /** The offset is the first index of the storage that is used. */
              private final int offset;

              /** The count is the number of characters in the String. */
              private final int count;

              /** Cache the hash code for the string */
              private int hash; // Default to 0
                0
                > а массивы содержат только ссылки на объекты, разве нет?
                нет, тогда бы размер любого массива был — countof(array) * sizeof(Pointer), а это не так.
                да и глупо так делать, new[] выделяет сразу кусок под все объекты.
                а разница заключается в том, что классы отличаются, Integer хранит один набор полей (скажем 4 int-поля), а String — другой (3 int-поля и 10 char'ов, к примеру).
                  +1
                  new Integer[] выделяет память только под указатели, поэтому размер массива-то как раз примерно «countof(array) * sizeof(Pointer)». Но в сабже память считается вместе с самими объектами, которые создаются отдельно в цикле (см. исходники).
                    0
                    ужаснах)
                    хотя для джавы это не так критично, с предвыделенной из системного пула памятью.
                      +1
                      Иначе это и не может для полиморфных объектов. Если создается, например, массив Shape[], то там могут быть и Point и Circle и Polygon, совершенно разные объекты с различными полями и конструкторами.

                      Конечно, в C++ можно сделать new Shape[N], но кому такой массив нужен? Надо делать массив указателей (для полиморфных объектов, а не просто структур), а в Яве фактически все объектные переменные как указатели.
                        0
                        речь идёт именно о «new Class[N]».
                        а не о «new Class[]».
                        во втором случае само собой дозволяется в таком массиве хранить классы-потомки, и линейное выделение памяти невозможно и неэффективно, ибо размеры объектов разные.
                          0
                          Ниасилил разницы new Class[N] и new Class[]. В Яве разницы нет. А в С++ что такое new Class[]?
                            0
                            Автор наверное имел ввиду, что в C++
                            Shape* shapes = new Shape[10];

                            круче чем

                            Shape[10] shapes;
                              +1
                              кроме Shape в обоих вариантах ничего в массив не поместить, если я ничего не путаю, давно на С++ не пишу
                        0
                        ужаснах)

                        Насколько я понимаю, этот «ужас» позволяет лучше работать когда память сильно фрагментирована.
                  0
                  Тут вобще всё страшно смешано, базовые типы — классы, коллекции и с теми и с другими. У простого смертного возникнет уйма вопросов вида «А почему так». Автору надо было как то разделить таблицу на какие то логические группы.

                  И ещё такой вопрос, я уже несовсем точно помню, но разве ArrayList(1024) не выравнивается до какого то другого значения?
                0
                Помнится, меня еще на Ява конференции поразил доклад, что сортировка массива интов быстрее сортировки массива Integer раза в 3, потому что Collection.sort использует разные алгоритмы для базовых типов и для объектов.
                Посмотрел я тут на масштаб бедствия с памятью и думаю, может сделать врапперы для списков базовых типов. Что-то вроде IntArrayList ~= ArrayList. Аналогично IntHashMap<int, V> ~= HashMap<int, V> итп. Под частную задачу можно получить приличный перформанс и мемори буст.
                  +1
                  Поздравляю, вы придумали Trove ;-)
                    0
                    Они пишут, что реализцют collections api. То что я предлагаю его не реализует вродебы.
                      0
                      Commons Primitives
                        0
                        Спасибо за наводку! Ушел тестить скорость…
                        0
                        С утра непонятливый. Что вы хотели сказать «IntArrayList ~= ArrayList»? и в чем состоит ваша идея?
                          0
                          Это не вы непонятливый, это парсер порезал генерик после ArrayList<int>
                          А писал я с сафари айпэда, который (сафари, не айпэд) пока я писал этот небольшой коммент успел упасть 2 раза…

                          boolean contains(int o);

                          IntIterator iterator();

                          int[] toArray();

                          boolean add(int e);
                        0
                        Предположительно все это должен знать любой JAVA разработчик

                        Что именно? Знать приведенную таблицу наизусть? :) Или просто понимать, чем int от Integer отличается и что такое строки и символы в Java?
                          +1
                          Да уж, есть есть гораздо более важные знания для разработчика. Например, как правильно реализовать equals() и hashCode() для persistence entities — сколько народу на собеседованиях ловятся на том, что думают, раз Блока прочитали, значит все про Java знают.

                          Размеры структур данных, может быть, имеют значение в случае разработки под эмбеддед системы, но даже там далеко не во всех случаях — уж Андроид с устройствами с 256мб памяти и выше к Эмбеддед относится лишь отчасти.
                          0
                          Это справедливо только для Java? На C# всегда думал, что int — это ключевое слово для C#, а Integer для .NET. А по сути это одно и тоже. Ваша статья меня напугала ))
                            0
                            Возможно, Integer из Java — это упакованный int/
                              –1
                              int и Integer, string и String, bool и Boolean и др. — это всё одно и тоже без исключений. Просто написание разное. (с) Рихтер
                                0
                                Как это — «одно и то же без исключений»?
                                0
                                Я вас сейчас ещё сильнее напугаю. Разница между примитивными типами и классами-оболочками не только в весе. Они ещё и хранятся по разному. Первый в стеке, а вторые в куче.
                                Страшно?
                                0
                                Интересно, что byte[], short[], int[] и long[] логично весят по-разному (~2 раза), Short[], Integer[], Long[] — одинаково и много, а Byte[] — намного меньше. Какое-то хитрое выравнивание памяти в объектах.
                                  +1
                                  Byte[] намного меньше, т.к. новые объекты типа Byte не создаются — их всего 256, и они все закэшированы.
                                  Объекты типа Short, Integer, Long занимают одинаково по 16 байт (на 32-битной платформе), т.к. заголовок объекта в HotSpot состоит из 8 байт, и сами объекты аллоцируются с выравниванием в 8 байт.
                                    +1
                                    Тогда думаю критично, как инициализируется Byte[]. Если делать new Byte(i), то, вероятно, кэш не сработает.
                                      0
                                      Да, тут та же ситуация, что и со String.
                                  0
                                  Интересная информация, спасибо, добавил в избранное.
                                    0
                                    Все-таки интересно почему размер Double[] увеличился, а Integer[] нет — у них же суть одна?..
                                      +10
                                      Каждый раз, когда ты пишешь int i вместо short i, сотни пользователей вынуждены докупать планку памяти.
                                        +6
                                        … и умирает котенок
                                          0
                                          Тогда уж лучше byte. Потому что в результате случайного автобоксинка short станет Short, а оно по размеру ничем не отличается от Integer. Хотя это странно… неужели они везде используют int?
                                          0
                                          А для PHP, Javascript подобных табличек нет? Недавно обнаружил, что $a=''; забирает 168 байт.
                                            0
                                            Преждевременная оптимизация зло, но знать такие вещи конечно нужно :)

                                            Only users with full accounts can post comments. Log in, please.