Сколько памяти занимает массив java
Перейти к содержимому

Сколько памяти занимает массив java

  • автор:

Как JVM понимает, что определенный объект занимает определенное количество байтов памяти?

Мой иначальный вопрос следующий — почему существует различие в механизме примитивных и ссылочных переменных? Почему примитивные переменные хранят адресс, по которому можно получить значение, а ссылочные переменные хранят адресс(указатель), по которому можно получить адресс объекта в хипе?

Начал гуглить, везде пишут: потому что размер объекта JVM знать не может(мол в примитивах понятно сколько длина последовательности байтов). А как указатель помогает в этом случае? Что поменялось кроме того, что у тебя есть дополнительный адресс-прослойка?

Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

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

Узнать сколько занимает памяти объект.
Здравствуйте. Кто нибудь в курсе, как можно узнать сколько "весит" экземпляр написанного мной.

Как выделить определенное количество памяти?
как выделить определенное количество памяти? (С#) какую структуру лучше использовать? список? стек.

528 / 263 / 70
Регистрация: 11.12.2016
Сообщений: 1,223

ЦитатаСообщение от Artmal Посмотреть сообщение

Как JVM понимает, что определенный объект занимает определенное количество байтов памяти?

Ну вы же как-то создаете этот самый объект, происходит инициализация полей.. примитивов и ссылочных данных. Да и зачем ему понимать, мы же не юзаем метод size() для отдельных объектов?!
Возможно дело в области видимости и жизненном цикле. У ссылки есть жизненный цикл а у примитива нет. К примитиву есть доступ через ссылку (либо через экземпляр либо через статик, напримет статик поле), и удалив ссылку мы не паримся с удалением примитивов к которым через нее имели доступ к примитивам.

ЦитатаСообщение от Artmal Посмотреть сообщение

Мой иначальный вопрос следующий — почему существует различие в механизме примитивных и ссылочных переменных?

Так возможно быстрее работает. Зачем засорять быстрый стэк ненужными примитивами и следить и управлять ими. Все в кучу.

Эксперт Java

3638 / 2970 / 918
Регистрация: 05.07.2013
Сообщений: 14,220

Не надо об этом думать от слова совсем.
Но если шило в ноге, то гуглить, кстати, легко https://www.quora.com/Why-does. ed-objects

Эксперт функциональных языков программированияЭксперт Java

4467 / 2701 / 484
Регистрация: 28.04.2012
Сообщений: 8,558

Лучший ответ

Сообщение было отмечено KEKCoGEN как решение

Решение

ЦитатаСообщение от Artmal Посмотреть сообщение

почему существует различие в механизме примитивных и ссылочных переменных?

Потому что иметь одну семантику для объектов проще, чем две.
Но для примитивных типов она избыточна, т.к.
– они достаточно малы, чтобы выделять под них память на стэке и копировать их при передаче в виде аргументов функции или возврате в качестве результата функции
– они иммутабельны, соответственно структурное равенство и равенство идентичности для них эквиваленты, а значит нет разницы между использованием по ссылке или по значению
– из всего этого вытекает, что нет нужды напрягать GC дополнительно кучей значений примитивных типов.

ЦитатаСообщение от Artmal Посмотреть сообщение

потому что размер объекта JVM знать не может

Ещё как может и знает. JVM включает в себя и менеджер памяти, как ни странно.

ЦитатаСообщение от Artmal Посмотреть сообщение

А как указатель помогает в этом случае?

А указатель помогает следующим образом:

Допустим, мы хотим описать односвязный список:

1 2 3 4
class ListT> { T head; ListT> tail; }

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

Кроме это примера, ЕМНИП, есть ещё нюансы при приведении объекта, созданного на стэке, к интерфейсному типу. Ты можешь подробней узнать обо всём этом у плюсовиков.

87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь

Сканирование байтов в памяти, и получение начального адреса байтов
Привет форумчане! У меня вопрос, как просканировать память у процесса так, чтобы получить адрес.

Определить количество байтов, которые занимают в памяти переменные данных типов
Здравствуйте. Помогите пожалуйста с лабораторной. В языке С++ полный ноль, ничего не понимаю.

Выделение памяти под определенное количество массивов
Задача такая. В первой строке во входном потоке число N(1<=N<=100).Следующие N строк содержат.

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

Все мы знаем, что язык программирования Java является чисто объектным языком. Все сущности, с которыми нам приходится иметь дело и осуществлять какие-либо манипуляции, являются объектами (за исключением примитивов), в том числе и массивы. То бишь, если говорить совсем уж простыми словами, то любой массив является конкретным объектом в памяти. Java является сильно типизированным языком. Хоть и градация на языки со слабой и сильной типизацией данных является весьма условной, но Java, так или иначе, больше относится к языкам с сильной типизацией. Это ведёт нас к тому, что все данные имеют свой фиксированный тип (или класс, если говорить в терминах ООП). Вот здесь и вся загвоздка! Мне всегда хотелось узнать, каким образом описываются массивы, как некоторые абстрактные сущности, на физическом уровне. Я понимаю, что невозможно найти готовый класс, в котором бы была описана структура массивов, по той простой причине, что данная сущность является одной из фундаментальных (на равне с примивными типами данных) и её реализация спрятана где-то на уровне JVM или в каком-то другом месте. Давайте рассмотрим тривиальный пример. Мы знаем, что размер любого массива является фиксированным и определяется на этапе создания самого массива. Сведения о размере массива хранятся в целочисленной переменной с одноимённым названием length. Сразу же возникает вопрос относительно этого поля. Откуда оно взялось? Где можно проследить всю эту внутреннюю логику (если можно так выразиться)? Идём далее. Создали массив в памяти, при этом сразу же указали его размер. Размер массива соответствует количеству однотипных элементов, которые могут храниться в этом массиве. И тут опять-таки вопрос. По какой логике JVM определяет количество элементов, которое нам необходимо? Точнее не совсем так. Понятное дело, что мы сами указываем размер массива, но разве количество полей для отдельно взятого типа данных не должно быть фиксированным?! Есть ли какой-нибудь код (пусть даже псевдокод), который мог бы хоть немного пролить свет на данный вопрос.

Отслеживать

13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков

Реализация массивов — Java: Массивы

Когда мы говорим про примитивные типы данных, такие как int или double, то, на интуитивном уровне, все довольно понятно. Под каждое значение выделяется некоторое количество памяти в соответствие с типом, в которой и хранится само значение. А как должна выделиться память под хранение массива? И что такое массив в памяти? На уровне хранения понятия «массив» не существует. Массив представляется цельным куском памяти, размер которого вычисляется по формуле «количество элементов» * «количество памяти под каждый элемент». Из этого утверждения есть два интересных вывода:

  • Размер массива — это фиксированная величина. Те динамические массивы, с которыми мы имеем дело, во многих языках реализованы уже внутри языка, а не на уровне железа
  • Все элементы массива имеют один тип и занимают одно и то же количество памяти. Благодаря этому появляется возможность простым умножением (по формуле, описанной ниже) получить адрес той ячейки, в которой лежит нужный нам элемент. Именно это происходит под капотом, при обращении к элементу массива под определенным индексом

Фактически, индекс в массиве — смещение относительно начала куска памяти, содержащего данные массива. Адрес, по которому расположен элемент под конкретным индексом, рассчитывается так: начальный адрес + индекс * количество памяти, занимаемое одним элементом:

// Инициализация массива из пяти элементов типа int // int занимает 4 байта // Общее количество памяти выделенное под массив int * 5 = 4 * 5 = 20 байт int[] numbers = 19, 10, 8, 17, 9>; numbers[3]; // 17 

Адрес элемента, соответствующего индексу 3, вычисляется так: начальный адрес + 3 * 4 (размер типа данных int). Начальный адрес — это адрес ячейки памяти, начиная с которой располагается массив. Он формируется во время выделения памяти под массив. Ниже пример расчета адресов памяти под разные элементы массива numbers:

Рассмотрим еще раз определение массива:

// Первый элемент // Начальный адрес + 4 * 0 = начальный адрес numbers[0]; // 19 // Начальный адрес + 4 * 1 = начальный адрес + 4 // То есть сместились на 4 байта numbers[1]; // 10 // Начальный адрес + 4 * 2 = начальный адрес + 8 // То есть сместились на 8 байт numbers[2]; // 8 // Последний элемент // Начальный адрес + 4 * 4 = начальный адрес + 16 // То есть сместились на 16 байт // И сам элемент занимает 4 байта. В сумме как раз 20 numbers[4]; // 9 

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Размеры массивов в Java

Размеры объектов в Java уже обсуждались на Хабре, например, здесь или здесь. Мне бы хотелось подробнее остановиться на размерах многомерных массивов — простая вещь, которая для меня стала неожиданной.

Оптимизируя вычислительный алгоритм по памяти, я наткнулся на то, что при определённых (вполне разумных) входных параметрах создаётся массив float[500][14761][2]. Сколько он может занимать в памяти (на HotSpot 1.6.0_26 32bit, если кому интересно)? Я примерно прикинул, что = = плюс какой-то оверхед. Решив проверить, как на самом деле, я воспользовался Eclipse Memory Analyzer (невероятно волшебная вещь, рекомендую!) и обнаружил, что «Retained Heap» для этого массива составляет ! Неплохой оверхед — 350%. Посмотрим, почему так получилось.

Я поискал, что на эту тему пишут в Интернете, и наткнулся на довольно понятную статью на английском «How to calculate the memory usage of a Java array». Вкратце суть изложения такая:

  • Всякий Java-объект имеет оверхед 8 байт;
  • Java-массив имеет дополнительный оверхед 4 байта (для хранения размера);
  • Ссылка имеет размер 4 байта;
  • Размер всех объектов выровнен по 8 байт;
  • Многомерный массив — это массив ссылок на массивы.

Этого знания достаточно. Итак мы имеем в конце цепочки массивы float[2]. Их размер — это 2 float (по 4 байта) + 12 байт оверхеда — 20 байт. Выравниваем до 8 — получается 24 байта. Всего у нас таких массивов создано в куче — штук. Итого они весят байт.

Затем у нас есть массивы float[14761][] — массивы из ссылок на другие массивы. Каждый такой массив занимает ссылки (по 4 байта) + 12 байт оверхеда — байт (делится на 8 — выравнивать не надо). Всего этих массивов 500 штук, значит они вместе весят байт.

Наконец, у нас есть собственно тот массив, который мы завели — float[500][][] — массив из 500 ссылок на двумерные массивы. Он занимает = , да ещё 4 байта выравнивания — байт.

Складываем, что получилось: = — как раз то число, которое показал Memory Analyzer.

Сразу же пришло в голову очевидное решение: упорядочить измерения массива по возрастанию. Сделаем float[2][500][14761] и алгоритм от этого никак не пострадает. Какой размер получится в этом случае?

  • Массивы float[14761]: = байт, всего таких массивов, итого байт.
  • Массивы float[500][]: = , после выравнивания — , всего 2 таких массива, итого байта.
  • Массив float[2][][]: = 20, после выравнивания — 24 байта.

Отсюда следует правило большого пальца: если размеры массива по измерениям хотя бы примерно известны заранее, следует упорядочивать измерения по возрастанию. Кроме того, обязательно используйте анализаторы памяти: узнаете много нового о своей программе.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *