Чи мають масиви Java максимальний розмір?


214

Чи існує обмеження кількості елементів, який може містити масив Java? Якщо так, то що це?


5
Ви прийняли неправильну відповідь, просто спробуйте виділити такий довгий масив (і ні, у мене не вистачає пам'яті).
maaartinus


Відповіді:


184

Я не бачив правильної відповіді, хоча це дуже легко перевірити.

У недавньому HotSpot VM правильна відповідь Integer.MAX_VALUE - 5. Як тільки ви вийдете за межі цього:

public class Foo {
  public static void main(String[] args) {
    Object[] array = new Object[Integer.MAX_VALUE - 4];
  }
}

Ви отримуєте:

Exception in thread "main" java.lang.OutOfMemoryError:
  Requested array size exceeds VM limit

57
Я вважаю, що ідея малолітражних прав не має сенсу, якщо ми не хочемо спростувати відповіді, які є простими та просто неправильними . Чи має значення різниця в п'ять байтів насправді в реальному світі, НІ, звичайно, ні. Але мене хвилює те, що люди готові дати відповідь «авторитетно», навіть не намагаючись переконатися, чи справді це працює. Що стосується обмеження пам'яті, ну DUH. Це як би ви запитали мене "скільки винограду можна з'їсти?" і я сказав: "ну, це залежить від того, скільки я маю в холодильнику на той час".
Кевін Бурліон

7
Чи знаєте ви, чому він не дасть вам цих п'яти байтів? Це обов'язково щось, що завжди відбувається на Java, чи це може бути просто пов'язано з пам'яттю вашого комп'ютера чи щось таке?
Таймон

17
@Kevin Bourrillion: Це, здається, змінилося, за допомогою Oracle 1.7.0_07 я можу виділити до MAX_VALUE-2елементів. Це не залежить від того, що я виділяю, і мені дуже цікаво, для чого VM може використовувати два "речі" (довжина не вміщується в 2 байти).
maaartinus

3
@ TomášZato пізніше, у Integer.MAX_VALUE+1вас буде ціле переповнення. Розміри масивів у Java - це int, ні long; незалежно від того, який тип даних ви зберігаєте у своєму масиві, байтах чи посиланнях. Рядки - це лише посилання на об'єкт.
Мав QUIT - Anonymous-Mousse

8
Максимальна кількість елементів у масиві в JDK 6 і вище - Integer.MAX_VALUE - 2= 2 147 483 645. Java успішно виділяє такий масив, якщо ви запускаєте його -Xmx13G. Це не вдається, OutOfMemoryError: Java heap spaceякщо ви проїдете -Xmx12G.
Олексій Іванов

127

Це, звичайно, повністю від ВМ.

Переглядаючи вихідний код OpenJDK 7 і 8 java.util.ArrayList, .Hashtable, .AbstractCollection, .PriorityQueue, і .Vectorви можете побачити це твердження повторюється:

/**
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

який додав Мартін Буххолц (Google) 2010-05-09 ; переглянув Кріс Хегарті (Oracle).

Отже, напевно, можна сказати, що максимальне "безпечне" число було б 2 147 483 639 ( Integer.MAX_VALUE - 8), і "спроби виділити більші масиви можуть призвести до OutOfMemoryError ".

(Так, окрема заява Buchholz не включає підтвердження підтвердження, тому це розраховане звернення до влади. Навіть у самій OpenJDK ми можемо побачити код, return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;який показує, що MAX_ARRAY_SIZEще не має реального використання.)


І навіщо нам додати -8?
JohnWinter

@Pacerier. Чи не слід цей MAX_ARRAY_SIZE застосовувати лише тоді, коли ви використовуєте ArrayList? Це відрізняється від використання масиву типу int [] array = new int [some_value_here]; чи не так? Чому константа, визначена в ArrayList, може бути застосована до звичайного масиву (визначеного за допомогою [])? Вони однакові за лаштунками?
Тіаго

1
@Tiago, Ні, сам код не має нічого спільного з максимальним розміром масивів. Це просто претензія.
Pacerier

@JohnWinter, Цитата зазначає "Деякі віртуальні машини резервують деякі масиви заголовків у масиві". Таким чином, -8це пов'язано з байтами, зайняті зарезервованими словами заголовка.
Pacerier

38

Насправді є два межі. Один, максимальний елемент, який може індексуватися для масиву, і, два, об'єм пам'яті, доступної вашій програмі. Залежно від обсягу доступної пам’яті та обсягу, який використовується іншими структурами даних, ви можете досягти межі пам’яті, перш ніж досягти максимального адресованого елемента масиву.


27

Переходимо до цієї статті http://en.wikipedia.org/wiki/Criticism_of_Java#Large_arrays :

Java піддавали критиці за те, що вона не підтримує масиви більш ніж 2 31 −1 (приблизно 2,1 мільярда) елементів. Це обмеження мови; У розділі 10.4 специфікації мови Java зазначено, що:

Масиви повинні бути індексовані значеннями int ... Спроба отримати доступ до компонента масиву з великим значенням індексу призводить до помилки часу компіляції.

Підтримка великих масивів також вимагає змін до СВМ. Це обмеження проявляється в таких областях, як колекція, обмежена 2 мільярдами елементів та неможливість зберігання файлів карт пам'яті, більших за 2 Гб. Java також не вистачає справжніх багатовимірних масивів (безперервно виділяються одиничні блоки пам'яті, до яких звертається один індикатор), що обмежує продуктивність для науково-технічних обчислень.


6
У Java не вистачає синтаксичного цукру для багатовимірних масивів, але ви все одно можете "мати" їх з невеликим примноженням (якщо тільки загальний розмір масиву не перевищив вищезгадану межу)
kbolino

11

Масиви індексуються невід'ємним цілим числом, тому максимальний розмір масиву, до якого ви можете отримати доступ, був би Integer.MAX_VALUE. Інша справа - як великий масив ви можете створити. Це залежить від максимальної пам’яті, доступної для вашого JVMта типу вмісту масиву. Кожен елемент масиву має його розмір, наприклад. byte = 1 byte, int = 4 bytes,Object reference = 4 bytes (on a 32 bit system)

Отже, якщо у вас 1 MBна комп'ютері доступна пам'ять, ви можете виділити масив byte[1024 * 1024]абоObject[256 * 1024] .

Відповідаючи на ваше запитання - Ви можете виділити масив розміру (максимально доступна пам'ять / розмір елемента масиву).

Підсумок - теоретично максимальний розмір масиву буде Integer.MAX_VALUE. Практично це залежить від того, скільки пам’яті у вас JVMє і яка частина вже розподілена на інші об’єкти.


3

Я намагався створити такий байтовий масив

byte[] bytes = new byte[Integer.MAX_VALUE-x];
System.out.println(bytes.length);

З цією конфігурацією запуску:

-Xms4G -Xmx4G

І версія java:

Версія Openjdk "1.8.0_141"

OpenJDK середовище виконання (збірка 1.8.0_141-b16)

64-бітний VM сервера OpenJDK (збірка 25.141-b16, змішаний режим)

Він працює лише для x> = 2, що означає максимальний розмір масиву Integer.MAX_VALUE-2

Значення вище цього дають

Виняток у потоці "main" java.lang.OutOfMemoryError: Запитаний розмір масиву перевищує обмеження VM на Main.main (Main.java:6)


2

Так, у масиві java існує обмеження. Java використовує ціле число в якості індексу для масиву, а максимальне ціле число для JVM - 2 ^ 32. тож ви можете зберігати 2147 483 647 елементів у масиві.

Якщо вам потрібна більше максимальної довжини, ви можете використовувати два різних масиви, але рекомендований метод - це збереження даних у файл. тому що для зберігання даних у файлі немає обмежень. оскільки файли, що зберігаються у ваших драйверах пам’яті, але масив, зберігаються в JVM. JVM надає обмежений простір для виконання програми.


1

Максимальна кількість елементів arrayє (2^31)−1або2 147 483 647


5
Java не може виділити розмір масиву Integer.MAX_VALUE - 1, ви отримаєте "java.lang.OutOfMemoryError: Запитаний розмір масиву перевищує обмеження VM". Максимальна кількість елементів у JDK 6 і вище становить Integer.MAX_VALUE - 2= 2 147 483 645.
Олексій Іванов

0

Насправді це обмеження Java, обмежуючи його в 2 ^ 30-4, будучи 1073741820. Не 2 ^ 31-1. Не знаю чому, але я перевірив це вручну на jdk. 2 ^ 30-3 все ще кидає vm, за винятком

Редагувати: фіксовано від -1 до -4, встановлено прапорець у вікні jvm


Ви використовуєте 32-розрядний JVM. Використовуйте 64-розрядний JVM, і межа JVM буде близьким до 2 ^ 31. (Вам також потрібен купі місця, яке не є типовим, і це вплине на вашу фізичну пам'ять.)
dave_thompson_085
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.