2010-01-20 3 views
70

У меня есть объявление массива, как это:Является ли массив примитивов Java хранимым в стеке или куче?

int a[]; 

Здесь a является массивом примитивного int типа. Где хранится этот массив? Он хранится в куче или стеке? Это примитивный тип int, все примитивные типы не хранятся в куче.

+35

Это не массив. Это ссылка на массив. Сама эта ссылка может быть сохранена в куче, если она является членом класса или объекта или в стеке, если это локальная переменная в методе. И примитивные типы могут быть сохранены в куче, если они являются членами класса или объекта. – UncleO

ответ

32

Она будет храниться на кучного

потому, что массив является объектом Java.

EDIT. А если у вас есть

int [] testScores; 
testScores = new int[4]; 

Думай этого кода, как говорят компилятору, «Создание объекта массива, который будет содержать четыре Интс, и назначить его ссылочной переменной с именем testScores также , продолжайте и установите для каждого элемента int значение 0. Спасибо. "

+2

И ссылочная переменная с именем testScores (указывающая на массив в куче) будет находиться в стеке. – Zaki

+8

Код только говорит «Спасибо», если вы предоставите компилятор опции '-g'. В противном случае он будет оптимизирован. – mob

+0

@mob Вы делаете предположение, что это единственный код. Вероятно, лучше предположить, что эти две строки являются частью более крупной программы, которая фактически использует массив. –

18

Это массив примитивных типов, которые сами по себе не является примитивным. Хорошее эмпирическое правило - когда задействовано новое ключевое слово, результат будет в куче.

132

Как сказал гурукулки, он хранится на куче. Тем не менее, ваш пост предположил недоразумение, вероятно, из-за того, что какой-то благими намерениями человек пропагандировал миф о том, что «примитивы всегда живут в стеке». Это неверно. Локальные переменные имеют свои значения в стеке, но не все примитивные переменные являются локальными ...

Например, рассмотрим такую ​​ситуацию:

public class Foo 
{ 
    int value; 
} 
... 

public void someOtherMethod() 
{ 
    Foo f = new Foo(); 
    ... 
} 

Теперь, где же f.value живут? Миф предположил бы, что это на стеке, но на самом деле это часть нового объекта Foo и живет на куче . (Обратите внимание, что значение f само является ссылкой и живет в стеке.)

Оттуда это простой шаг к массивам. Вы можете думать о массиве, как просто быть много переменных - так new int[3] немного как иметь класс этой формы:

public class ArrayInt3 
{ 
    public readonly int length = 3; 
    public int value0; 
    public int value1; 
    public int value2; 
} 

На самом деле, это гораздо сложнее, чем это. Разделение стека/кучи в основном является детальностью реализации - я считаю, что некоторые JVM, возможно экспериментальные, могут сказать, когда объект никогда не «ускользает» от метода и может выделить весь объект в стеке. Тем не менее, это концептуально на кучу, если вы решите заботиться.

+1

Об «escape-анализе» в Java: http://blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead/ В нем говорится, что он присутствует с раннего доступа выпуск JDK 6 Update 14 и включен по умолчанию, поскольку JDK 6 Update 23. –

+0

ли это что-то изменить, если массив является открытым статическим окончанием? Разве это не должно быть частью постоянного пула? – Malachiasz

+0

@Malachiasz: Нет. Массив никогда не является константой. –

14

Я просто хотел поделиться несколькими тестами, которые я провел по этому вопросу.

массив размером 10000000

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 МБ, что 10m * SizeOf (двойной).

Но если мы используем двойной вместо двойного

public static void main(String[] args) { 
    memInfo(); 
    Double a[] = new Double[10000000]; 
    memInfo(); 
} 

выход покажет 40MB. У нас есть только двойные ссылки, они не инициализированы.

Заполнение его с двойным

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(); 
} 

Still 40Мб. Потому что все они указывают на тот же 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] = qq.doubleValue(); 

эквивалентно

a[i] = Double.valueOf(qq.doubleValue()); 

что эквивалентно

a[i] = new Double(qq.doubleValue()); 

Поскольку мы каждый раз создаем новые объекты Double, мы продуваем кучу. Это показывает значения внутри класса Double, хранящиеся в куче.

Смежные вопросы