Массивы на разных языках-хранить ссылки или необработанные объекты?

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

рассмотрим следующий код Java:

String a = "hi";
String b = "there";
String c = "everyone";
String[] array = {a, b, c};

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

Теперь рассмотрим этот:

String[] array = {"hi", "there", "everyone"}

Я бы предположил, что в этой ситуации строки существуют где-то со всеми другими константами в памяти, а затем массив содержит ссылки на эти константы в памяти? Итак, опять же, в raw-памяти массив не выглядит как ['h', 'i', '', 't', 'h', 'e', 'r', 'e'... (etc)]. (используя прекращение c-типа как раз для удобства). Скорее, это больше похоже на ['a83a3edf' ,'a38decd' ... (etc)], где каждый элемент представляет собой ячейку памяти (источник).

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

теперь рассмотрим C:

char *a = "hi";
char *b = "there";
char *c = "everyone";
char *array[] = {a, b, c};

приведенный выше код функционально эквивалентен Java выше - то есть массив содержит ссылки (указатели) на какое-либо другое место памяти. Как и Java, объекты, на которые указывают не обязательно смежные.

однако, в следующем коде C:

struct my_struct array[5];  // allocates 5 * size(my_struct) in memory! NOT room for 5
                            // references/pointers, but room for 5 my_structs.

структуры в array смежно расположены в необработанной памяти.

теперь для моих конкретных вопросов:

  1. был ли я прав в своем предположении, что в Java массивы всегда должны содержать ссылки, поскольку программист всегда имеет доступ только к ссылкам на Java? Как насчет необработанных типов данных? Будет ли это работать по-другому? Будет массив ints в Java выглядит так же, как один в C в необработанной памяти (кроме Object класс cruft Java добавит)?

  2. в Java нет способа для программиста гарантировать непрерывное выделение памяти объектов? Это может произойти случайно или с большой вероятностью, но программист не может гарантировать, что это будет так?

  3. в C программисты могут создавать необработанные массивы объектов (структур) смежно в памяти, как я показал выше, правильно?

  4. как другие языки справляются с этим? Я предполагаю, что Python работает как Java?

мотивация этого вопроса заключается в том, что я хочу получить четкое представление о том, что происходит на уровне необработанной памяти с массивами на этих языках. В основном для программистов-интервью. В предыдущем интервью я сказал, что массив (не на каком-либо языке, а вообще) содержит объекты в памяти, как ведра. Это было только после того, как я сказал Это, я понял, что это не совсем так, как работает на языке Java. Поэтому я хочу быть на 100% ясным.

спасибо. Дай мне знать, если что-то понадобится прояснить.

4 ответов


вы никогда не можете представить массивы как ведра смежных объектов в памяти, а скорее как непрерывные ссылки.

теоретически вы правы, на практике JVM не рандомизирует доступ к памяти. Он выделяет память последовательно и копирует объекты во время GC в порядке обнаружения (или в обратном порядке)

был ли я прав в своем предположении, что в Java массивы всегда должны содержать ссылки, поскольку программист только когда-либо имеет доступ ссылки на Java?

да, если у вас нет массива примитивов, конечно.

Как насчет необработанных типов данных? Будет ли это работать по-другому?

примитивы и ссылки непрерывны в памяти. Они в основном одинаковы.

будет ли массив ints в Java выглядеть так же, как один в C в необработанной памяти (кроме того, класс объектов cruft Java добавит)?

да.

в Java нет способа для программиста гарантировать непрерывное выделение памяти объектов?

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

это может произойти случайно или с большой вероятностью, но программист не может гарантировать, что это будет так?

правильно. Обычно у вас есть большие проблемы, когда вы смотрите на худшие задержки 0,1% или выше.

в C программисты могут создавать необработанные массивы объектов (структур) смежно в памяти, как я показал выше, правильно?

да. Вы также можете сделать это на Java, но вам нужно использовать память кучи. Существует ряд библиотек, которые поддерживают это, такие как Javolution, Chronicle, SBE.


низкоуровневые языки как C с памятью, и есть ли у вас указатель в другое место или значение прямо здесь. Убедитесь, что вы правильно обрабатываете распределение стека и кучи и не забудьте free() каждый указатель вы malloc().

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


to 1) в массивах java объекты и объекты и массивы хранятся в куче, так как куча не может быть непрерывной, поэтому массивы также не могут быть непрерывными.

4) в python вы можете создать непрерывный массив, если используете scipy


Я не могу говорить подробно о Java, хотя мое понимание заключается в том, что при следующем коде

int arr[] = new int[N];

локальная (стековая) переменная arr содержит ссылку на объект массива в куче, давая нам макет примерно так:

          +---+
     arr: |   |---+
          +---+   |
           ...    |
          +---+   |
      cp: |   |<--+  class pointer 
          +---+ 
     flg: |   |      flags
          +---+
     lck: |   |      locks
          +---+
      sz: |   |      size
          +---+
  arr[0]: |   |
          +---+
  arr[1]: |   |
          +---+
           ...
          +---+
arr[N-1]: |   |
          +---+

для массива примитивных типов значения хранятся непосредственно в arr[0], arr[1], etc. Для выбора типов классов, каждый элемент массива хранит ссылку на экземпляр этого класса, так есть еще один уровень косвенности. Сами ссылки хранятся смежно, но экземпляры, на которые они указывают, не являются (или, по крайней мере, не гарантированы).

массивы C и C++ намного менее сложны. Дается следующий код:

 int arr[N];

вы получите:

          +---+
  arr[0]: |   |
          +---+ 
  arr[1]: |   |
          +---+ 
           ...
          +---+
arr[N-1]: |   |
          +---+

в массиве C нет косвенности или метаданных. Там нет хранения, отведенного для объекта arr чтобы указать на первый элемент матрица. Если массив имеет auto extent (это означает, что он был объявлен в блоке, а не static), то память для элементов массива выделяется так же, как и для любой локальной переменной.

для любого типа T, T arr[N] выделяем N смежные элементы для хранения значений типа T. Если T это отвратительно struct тип,T a[N] магазинах N непрерывные примеры этого отвратительного struct тип.