Где массив сохраняется в памяти в java?

Если у меня есть функция, которая в этой функции объявляю:

Object arr[] = new Object[20];

Где хранятся arr и весь массив? кучи? стек? Имеет ли значение, если декларация находится в некоторой функции или в main()?

и скажем, что у меня также есть эти командные строки:

arr[0] = new String("abc");
arr[1] = new List();

где хранятся arr[0] и arr[1]?

Ответ 1

Диаграмма памяти:

Memory diagram

Коробки - это ячейки памяти (где двоичные числа могут быть сохранены).
Стрелки - это ссылки на память (т.е. Указатели).

Ответ 2

Теоретически, стек имеет единственный указатель на местоположение в куче, которое содержит сам массив. Сам массив представляет собой массив указателей, которые также указывают на местоположения в куче, которые содержат объекты, которые вы ссылаетесь.

В Java вы можете в значительной степени рассчитывать на то, что в любое время, когда вы говорите new ..., в куче создается пространство. Вообще говоря, каждый раз, когда вы объявляете переменную, компилятор резервирует пространство стека в контексте метода для этой переменной. Для собственных типов это пространство будет содержать фактические байты для представления значения. Для объектов и массивов эта переменная будет содержать ссылку на память.

Итак, например, следующие объекты имеют отдельные ячейки памяти, выделенные для них в куче:

new Object[20]
new String("abc")
new List() // This contains a reference to an initial array, which is also on the heap.

Обратите внимание, что существует очень мало случаев, когда new String("abc") предпочтительнее "abc", поскольку в литературе строковые литералы будут существовать в памяти пакета, а строки неизменяемы. Нет смысла выделять дополнительную память для точной копии строки, которая уже существует в памяти.

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

Ответ 3

В Java, в основном в любое время, когда вы используете ключевое слово new, вы выделяете пространство в куче для объекта, который нужно сохранить.

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

Итак, например:

                                    // This array object is
                                    // stored on the heap.
String[] arr                      = new String[5];
// This reference (arr) is stored
// in a variable on the stack.

В случае массива ссылочных типов, таких как Object[], выделенное пространство представляет собой смежный блок, достаточно большой, чтобы хранить сколько-нибудь ссылок, которые будет удерживать массив. Любая конкретная ссылка, такая как таковая в arr[0], сама укажет на другое место в куче, где хранится отдельный объект.

The array, somewhere on the heap:
[a*][b*][  ][  ][  ]

a (elsewhere on the heap):
"abc"

b (yet another heap location):
[A List object]

Единственное исключение - массивы примитивов, например int[]: в этом случае сам массив по-прежнему является непрерывным блоком в куче, но каждая позиция в массиве содержит только фактическое значение, а не ссылку на другое положение в куче.

Ответ 4

Массив из n строк -

  • Следующий список n ссылок на объекты в куче
  • n одиночные объекты String со ссылкой на массив в куче
  • n массивов символов в куче

В этом массиве также есть ссылка, которая может храниться в стеке или (как поле в классе) в куче