Как рассчитать использование памяти Java-массива

Если у меня есть:

int c[] = new int[10];

а также

int a[][] = new int[2][3];

и вообще

n*m*..*j массив

Как я могу рассчитать реальное использование памяти, учитывая также ссылочные переменные?

7 ответов

Решение

Если вы хотите точный ответ, вы не можете. По крайней мере, не так просто. Эта тема объясняет больше.

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

Для простой оценки вам следует использовать вычисления из других ответов и добавить 100-200 байтов.

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

Давайте возьмем ваш первый пример: int c[] = new int[N];

В соответствии с 64-битной моделью памяти, int составляет 4 байта, поэтому все элементы будут иметь размер 4*N байтов. В дополнение к этому, у Java есть 24-байтовые массивы и 8 байтов для фактического объекта массива. Так что это в общей сложности 32 + 4 * N байтов.

Для двумерного массива: int a[][] = new int[N][M];

Это в основном то же самое, просто каждый элемент в первом массиве является другим массивом размера M, поэтому вместо 4 у нас есть 32 + 4 * M, поэтому общий размер составляет 32 + (32 + 4 * M) * N.

Это правда, что обобщение для измерений D довольно сложно, но вы поняли идею.

Вы, вероятно, получите наилучшее приближение из этого: http://java.sun.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html

Эта статья, и эта всеобъемлющая демонстрирует / детализирует этот подход

Я знаю, что это старый вопрос, но у меня был такой же, и информация, представленная в этой ветке, мне не помогла. Источник, предоставивший мне необходимую информацию: https://www.javamex.com/tutorials/memory/array_memory_usage.shtml

Вот мой случай: у меня большой массив

int a[][] = new int[m][n];

где "большой" на самом деле вводит в заблуждение: m большое (3^18 = 387420489), но n маленькое (4). Я продолжал сталкиваться с проблемами памяти, которых я не понимал, так как m * n * 4 = 6198727824 (~6 ГБ), тогда как у меня 16 ГБ ОЗУ (и 12 разрешено для JVM с -Xmx12G). Ссылка, которую я только что поместил, дала мне ответ:

каждая из 10 строк имеет свой собственный 12-байтовый заголовок объекта, 4*10=40 байтов для фактической строки целых чисел и снова 4 байта заполнения, чтобы общее количество для этой строки кратно 8

Здесь память моего двумерного массива существенно отличается от 4 * m * n: здесь, поскольку n мало (4), размер каждой строки действительно отличается от 4 * n; если вы примените формулу, приведенную в ссылке (даже если она приблизительная), вы получите для каждой строки: 12 (заголовок) + 4 * 4 (четыре целых) + 4 (заполнение, кратное 8 байтам) = 32. Это вдвое больше, чем я ожидал, и объясняет, что я столкнулся с переполнением памяти.

Ответ Янна выше правильный, я перепроверил его через дамп кучи.

Вот данные, которые нам нужны для вычисления точного размера памяти массива (источник: https://www.javamex.com/tutorials/memory/array_memory_usage.shtml):

  • Размер выбранного типа Java (например: double = 8 байт) 'S'
  • Округление массива Java до кратного: 8 байтов 'q'
  • Размер ссылки Java: 4 байта 'R'
  • Размер заголовка массива Java: 12 байт 'H'

Форумы:

Для двойного [N] = (N * S + H) + (N * S + H) % q = 'x'

Для двойного [M][N] = [M * ​​(x + R) + H] + [M * ​​(x + R) + H] % q = 'y'

Например:

double[10] = (10 * 8 + 12) + (10 * 8 + 12) % 8 = 96 байт

double[10][10] = [10 * (96 + 4) + 12] + [10 * (96 + 4) + 12] % 8 = 1016 байт

Простое умножение базового примитивного типа (неверное) даст результат:

двойной [10] = 8 * 10 = 80 байт

двойной[10][10] = 8 * 10 * 10 = 800 байт

int[] или же int[][] не является примитивным типом данных. Это объект в Java. А с Объектом размер не может быть рассчитан сразу.

Для оригинального типа: базовый тип и размер байта

  • логическое 1
  • байт 1
  • символ 1
  • Int 4
  • плавать 4
  • длинный 8
  • двойной 8
  • Interger 24 (16 для экземпляра класса + 4 для int + 4 для выравнивания памяти)

в [M]: 24 + 4M

(16 для класса + 4 для сохранения размера массива + 4 для выравнивания памяти) + (для M размера double нам нужно 4 * M)

int [M][N]: (24+4M) + M*(24+4N) = 24+28M+4MN ~~~4MN

обрабатывать [M] [N] как размер M двойного массива a [N] плюс один дополнительный массив для хранения ссылки на начальную точку всех массивов размера M.

Другие вопросы по тегам