Производительность ArrayList<Integer> по сравнению с int[]

У меня есть миллион целых чисел, которые я хочу сохранить в структуре данных. Я хотел знать, является ли массив int (int[]) более эффективным, чем ArrayList. Есть ли какой-либо прирост производительности при использовании int[] вместо ArrayList? Я считаю, что ArrayList использует больше памяти, чем int[], но я не знаю, незначительна ли эта дополнительная память или нет.

Если бы я увеличил размер массива (с одного миллиона до одного миллиарда), изменился бы ответ? Является ли дополнительная память, используемая ArrayList, незначительной или нет?

ArrayLists Берите только объекты, поэтому вместо 1 млн 32-битных целых чисел, хранящихся в массиве, вы будете хранить 1 млн целочисленных объектов. Конечно, списки проще в использовании и позволяют легче манипулировать значениями, например добавлять, удалять, удалять и т. д. И они динамически растут по мере необходимости.
WJS 14.06.2024 02:39

@WJS Правда... ArrayList будет хранить 1 миллион целочисленных объектов. Но объект Integer должен быть эффективным и не занимать так много памяти. Насколько велики будут накладные расходы? Будет ли дополнительная память незначительной или немалой?

ktm5124 14.06.2024 02:49

Я бы рекомендовал вам сначала написать код, а затем оценить производительность, когда он будет готов. Начните со списка.

WJS 14.06.2024 03:06

Вот API ArrayList. В начале есть краткое примечание о производительности. Но remove требует, чтобы объекты, следующие за удаленным, были сдвинуты. Обратите внимание, что у него есть метод ensureCapacity.

Old Dog Programmer 14.06.2024 03:12
int[] использует минимальное пространство, тогда как список целочисленных объектов хранит ссылки на целочисленные объекты, каждый из которых содержит поле int.
Bohemian 14.06.2024 03:15

Также стоит рассмотреть возможность использования сторонних библиотек; например Guava Ints.asList(int[]), который оборачивает int[] как List<Integer> фиксированной длины

Stephen C 14.06.2024 03:28

Вы также можете рассмотреть IntBuffer, который имеет преимущества в производительности массива, но дает вам некоторые, но не все возможности списка.

VGR 14.06.2024 05:23

посмотрите здесь, чтобы получить информацию о производительности.

Marce Puente 14.06.2024 07:01

Проект Валгалла / Объекты ценностей должен устранить большинство/все различия, если/когда они возникнут.

DuncG 14.06.2024 08:52
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
9
114
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По умолчанию емкость ArrayList может в два раза превышать количество содержащихся в нем элементов. Итак, если вы знаете предполагаемый размер, укажите начальную вместимость . Если размер неизвестен, обрежьте, когда закончите добавлять элементы.

Однако основное различие между ArrayList<Integer> и int[] заключается в разнице между Integer и int: первый является объектом, и каждый объект хранит некоторые метаданные для JVM (тип среды выполнения, хеш-код идентификации и т. д.) в дополнение к своим полям. что делает его несколько больше обычного int. Размер этих метаданных не указан и может варьироваться. Вы можете измерить его следующим образом:

public class Test {
    
    static final int elements = 10_000_000;
    
    private static long usedMemory() {
        var r = Runtime.getRuntime();
        return r.totalMemory() - r.freeMemory();
    }
    
    static void measure(String name, Runnable code) {
        System.gc(); // clean up previous tests
        long start = usedMemory();
        code.run();
        long end = usedMemory();
        System.out.println(name + " ".repeat(35 - name.length()) + " used " + (double)(end - start) / elements + " bytes/element");
    }
    
    public static void main(String[] args) {
        measure("int[]", () -> { 
            var a = new int[elements];
        });
        measure("Integer[] with small numbers", () -> {
            var a = new Integer[elements];
            for (int i = 0; i < elements; i++) {
                a[i] = i % 64;
            }
        });
        measure("Integer[] with large numbers", () -> {
            var a = new Integer[elements];
            for (int i = 0; i < elements; i++) {
                a[i] = i;
            }
        });
        measure("ideal capacity ArrayList<Integer>", () -> {
            var a = new ArrayList<Integer>(elements);
            for (int i = 0; i < elements; i++) {
                a.add(i);
            }           
        });
        measure("auto sized ArrayList<Integer>", () -> {
            var a = new ArrayList<Integer>();
            for (int i = 0; i < elements; i++) {
                a.add(i);
            }
        });
    }
}

На моей JVM это печатает:

int[]                               used 4.1809328 bytes/element
Integer[] with small numbers        used 4.1949816 bytes/element
Integer[] with large numbers        used 20.7624576 bytes/element
ideal capacity ArrayList<Integer>   used 20.8476584 bytes/element
auto sized ArrayList<Integer>       used 30.3283208 bytes/element

То есть на этой JVM объект Integer занимает 16 байт, а ссылка на объект 4 байта (если бы моя куча была достаточно большой, вместо этого ей понадобилось бы 8 байт). Если Integer содержит небольшие числа, объекты Integer будут использоваться повторно, и вы платите только за ссылку. Напротив, если объекты Integer содержат большие числа, для каждого элемента создается новый Integer.

ArrayList идеальной емкости имеет размер массива ссылок. ArrayList с автоматическим ростом может быть в два раза больше, чем необходимо.

Сравнение производительности также будет зависеть от 1) того, создаются ли значения Integer с использованием Integer.valueOf(...) или автобокса или new Integer(...) 2) являются ли числа обычно небольшими (и, следовательно, кэшируются) или нет, и 3) использует ли ваша JVM 32-битную или 64-битную версию. Рекомендации. Ваша оценка пессимальна по отношению к 2.

Stephen C 14.06.2024 03:15

Однако... во всех случаях int[] будет занимать меньше места, чем ArrayList с тем же количеством элементов, даже если последний был обрезан с помощью trimToSize.

Stephen C 14.06.2024 03:20

@StephenC: Хорошая мысль, теперь я добавил для этого отдельный тестовый пример.

meriton 14.06.2024 03:32

Внимание: System.gc(); — это просьба, а не приказ. Сбор мусора (GR) может происходить, а может и не происходить. Сборщик мусора, если он действительно начинается, может не завершиться до продолжения работы вашего кода, в зависимости от реализации сборщика мусора. У нас нет контроля.

Basil Bourque 14.06.2024 16:34

Другие вопросы по теме