Как рассчитать использование памяти 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.