Хранится ли массив примитивов Java в стеке или куче?
85
У меня есть такое объявление массива:
int a[];
Вот aмассив примитивного intтипа. Где хранится этот массив? Он хранится в куче или стеке? Это примитивный тип int, все примитивные типы не хранятся в куче.
Это не массив. Это ссылка на массив. Сама ссылка может храниться в куче, если она является членом класса или объекта, или в стеке, если это локальная переменная в методе. И примитивные типы могут храниться в куче, если они являются членами класса или объекта.
uncleO
Ответы:
145
Как сказал гурукулки, хранится в куче. Тем не менее, ваш пост предполагает недоразумение, вероятно, из-за некоего благонамеренного человека, распространяющего миф о том, что «примитивы всегда живут в стеке». Это неправда. Локальные переменные имеют свои значения в стеке, но не все примитивные переменные являются локальными ...
Например, рассмотрим это:
publicclassFoo{
int value;
}
...
publicvoidsomeOtherMethod(){
Foo f = new Foo();
...
}
А где f.valueживет? Миф предполагает, что он находится в стеке, но на самом деле он является частью нового Fooобъекта и живет в куче. 1 . (Обратите внимание, что само значение fявляется ссылкой и находится в стеке.)
Отсюда легко перейти к массивам. Вы можете думать о массиве как о множестве переменных - new int[3]это немного похоже на класс такой формы:
publicclassArrayInt3{
public readonly int length = 3;
publicint value0;
publicint value1;
publicint value2;
}
1 На самом деле все сложнее. Различие стека / кучи в основном связано с реализацией - я считаю, что некоторые JVM, возможно, экспериментальные, могут определить, когда объект никогда не «ускользнет» из метода, и могут выделить весь объект в стеке. Однако концептуально это в куче, если вы решите позаботиться.
это что-то меняет, если массив является публичным статическим окончательным? Разве это не должно быть частью постоянного пула?
Malachiasz
@Malachiasz: Нет. Массив никогда не бывает константой.
Джон Скит
@JonSkeet: во всех известных мне версиях библиотеки Java каждая из Stringних поддерживается файлом char[]. Я считаю, что буквальные строки хранятся в общедоступном пуле констант; для оптимизации сборщика мусора это будет означать, что резервные массивы должны храниться аналогичным образом (в противном случае постоянный пул должен быть сканирован во время любого цикла сборщика мусора, где резервный массив в противном случае имел бы право на сбор).
supercat 08
@supercat: Да, в этом есть смысл. Но любой массив вы объявляете себя никогда не заканчивается, как часть постоянного бассейна.
Джон Скит
37
Он будет храниться в куче
потому что массив - это объект в java.
РЕДАКТИРОВАТЬ : если у вас есть
int [] testScores;
testScores = newint[4];
Думайте об этом коде как о сообщении компилятору: «Создайте объект массива, который будет содержать четыре целых числа, и назначьте его ссылочной переменной с именем testScores. Кроме того, продолжайте и установите каждый intэлемент в ноль. Спасибо».
И ссылочная переменная с именем testScores (указывающая на массив в куче) будет в стеке.
Zaki
11
Код говорит «Спасибо» только в том случае, если вы предоставляете эту -gопцию компилятору. В противном случае он будет оптимизирован.
Mob
1
@mob Вы делаете предположение, что это единственный код. Вероятно, лучше предположить, что эти две строки являются частью более крупной программы, которая фактически использует массив.
Code-Apprentice
22
Это массив примитивных типов, который сам по себе не является примитивным. Хорошее практическое правило заключается в том, что при использовании ключевого слова new результат будет в куче.
------------------------
max mem = 130.0 MB
total mem = 85.0 MB
free mem = 83.6 MB
used mem = 1.4 MB
------------------------
------------------------
max mem = 130.0 MB
total mem = 130.0 MB
free mem = 48.9 MB
used mem = 81.1 MB
------------------------
Как видите, размер используемой кучи увеличен на ~ 80 МБ, что составляет 10 м * sizeof (double).
Но если мы используем Double вместо double
publicstaticvoidmain(String[] args){
memInfo();
Double a[] = new Double[10000000];
memInfo();
}
На выходе будет 40 МБ. У нас есть только двойные ссылки, они не инициализируются.
Заполнение двойным
publicstaticvoidmain(String[] args){
memInfo();
Double a[] = new Double[10000000];
Double qq = 3.1d;
for (int i = 0; i < a.length; i++) {
a[i] = qq;
}
memInfo();
}
Еще 40МБ. Потому что все они указывают на один и тот же объект Double.
Инициализация с помощью double вместо
publicstaticvoidmain(String[] args){
memInfo();
Double a[] = new Double[10000000];
Double qq = 3.1d;
for (int i = 0; i < a.length; i++) {
a[i] = qq.doubleValue();
}
memInfo();
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Линия
a[i] = qq.doubleValue();
эквивалентно
a[i] = Double.valueOf(qq.doubleValue());
что эквивалентно
a[i] = new Double(qq.doubleValue());
Поскольку мы каждый раз создаем новые объекты Double, мы сдуваем кучу. Это показывает, что значения внутри класса Double хранятся в куче.
Ответы:
Как сказал гурукулки, хранится в куче. Тем не менее, ваш пост предполагает недоразумение, вероятно, из-за некоего благонамеренного человека, распространяющего миф о том, что «примитивы всегда живут в стеке». Это неправда. Локальные переменные имеют свои значения в стеке, но не все примитивные переменные являются локальными ...
Например, рассмотрим это:
public class Foo { int value; } ... public void someOtherMethod() { Foo f = new Foo(); ... }
А где
f.value
живет? Миф предполагает, что он находится в стеке, но на самом деле он является частью новогоFoo
объекта и живет в куче. 1 . (Обратите внимание, что само значениеf
является ссылкой и находится в стеке.)Отсюда легко перейти к массивам. Вы можете думать о массиве как о множестве переменных -
new int[3]
это немного похоже на класс такой формы:public class ArrayInt3 { public readonly int length = 3; public int value0; public int value1; public int value2; }
1 На самом деле все сложнее. Различие стека / кучи в основном связано с реализацией - я считаю, что некоторые JVM, возможно, экспериментальные, могут определить, когда объект никогда не «ускользнет» из метода, и могут выделить весь объект в стеке. Однако концептуально это в куче, если вы решите позаботиться.
источник
String
них поддерживается файломchar[]
. Я считаю, что буквальные строки хранятся в общедоступном пуле констант; для оптимизации сборщика мусора это будет означать, что резервные массивы должны храниться аналогичным образом (в противном случае постоянный пул должен быть сканирован во время любого цикла сборщика мусора, где резервный массив в противном случае имел бы право на сбор).Он будет храниться в куче
потому что массив - это объект в java.
РЕДАКТИРОВАТЬ : если у вас есть
int [] testScores; testScores = new int[4];
Думайте об этом коде как о сообщении компилятору: «Создайте объект массива, который будет содержать четыре целых числа, и назначьте его ссылочной переменной с именем
testScores
. Кроме того, продолжайте и установите каждыйint
элемент в ноль. Спасибо».источник
-g
опцию компилятору. В противном случае он будет оптимизирован.Это массив примитивных типов, который сам по себе не является примитивным. Хорошее практическое правило заключается в том, что при использовании ключевого слова new результат будет в куче.
источник
Я просто хотел поделиться несколькими тестами, которые я провел на эту тему.
Массив размером 10 миллионов
public static void main(String[] args) { memInfo(); double a[] = new double[10000000]; memInfo(); }
Вывод:
------------------------ max mem = 130.0 MB total mem = 85.0 MB free mem = 83.6 MB used mem = 1.4 MB ------------------------ ------------------------ max mem = 130.0 MB total mem = 130.0 MB free mem = 48.9 MB used mem = 81.1 MB ------------------------
Как видите, размер используемой кучи увеличен на ~ 80 МБ, что составляет 10 м * sizeof (double).
Но если мы используем Double вместо double
public static void main(String[] args) { memInfo(); Double a[] = new Double[10000000]; memInfo(); }
На выходе будет 40 МБ. У нас есть только двойные ссылки, они не инициализируются.
Заполнение двойным
public static void main(String[] args) { memInfo(); Double a[] = new Double[10000000]; Double qq = 3.1d; for (int i = 0; i < a.length; i++) { a[i] = qq; } memInfo(); }
Еще 40МБ. Потому что все они указывают на один и тот же объект Double.
Инициализация с помощью double вместо
public static void main(String[] args) { memInfo(); Double a[] = new Double[10000000]; Double qq = 3.1d; for (int i = 0; i < a.length; i++) { a[i] = qq.doubleValue(); } memInfo(); } Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Линия
эквивалентно
что эквивалентно
a[i] = new Double(qq.doubleValue());
Поскольку мы каждый раз создаем новые объекты Double, мы сдуваем кучу. Это показывает, что значения внутри класса Double хранятся в куче.
источник
В языке программирования Java массивы являются объектами, создаются динамически и могут быть присвоены переменным типа Object.
http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html
источник