6

Как определить размер объекта в Java?

1

У меня есть приложение, которое читает CSV файл с большим количеством строк данных. Я предоставляю пользователю сводку о количестве строк на основе типов данных, но хочу убедиться, что не читаю слишком много строк и не вызываю ошибку OutOfMemoryError. Каждая строка соответствует объекту. Есть ли способ программно определить размер этого объекта? Существует ли ссылка, которая определяет, какого размера примитивные типы и ссылки на объекты для VM?

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

5 ответ(ов)

1

Вы случайно наткнулись на класс Java, называемый jdk.nashorn.internal.ir.debug.ObjectSizeCalculator, который уже присутствует в JDK и довольно прост в использовании. Этот класс может быть полезен для определения размера объектов в Java.

Вот пример его использования:

System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));

Результаты выполнения этого кода:

164192
48
16
48
416

Таким образом, вы можете видеть, сколько памяти занимает каждый из этих объектов. Например, TObjectIntHashMap занимает 164192 байта, тогда как примитивный тип int занимает всего 16 байт. Это может быть полезно для оптимизации использования памяти в ваших приложениях. Однако следует учитывать, что класс ObjectSizeCalculator находится в внутреннем пакете JDK и его использование не рекомендуется для производственного кода, так как он может измениться или быть удален в будущих версиях JDK.

0

Если вам нужно узнать, сколько памяти используется в вашей JVM и сколько её свободно, вы можете попробовать следующее:

// Получаем текущий размер кучи в байтах
long heapSize = Runtime.getRuntime().totalMemory();

// Получаем максимальный размер кучи в байтах. Куча не может превышать этот размер.
// Любая попытка выделить больше памяти приведет к OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Получаем количество свободной памяти в куче в байтах. Этот размер будет увеличиваться
// после сборки мусора и уменьшаться по мере создания новых объектов.
long heapFreeSize = Runtime.getRuntime().freeMemory();

Дополнение: Я подумал, что это может быть полезно, так как автор вопроса также упомянул, что хотел бы реализовать логику, которая будет "читать столько строк, сколько возможно, пока я не использую 32 МБ памяти".

0

Когда я работал в Twitter, я разработал утилиту для вычисления размера глубоких объектов. Она учитывает различные модели памяти (32-битные, сжатые oops, 64-битные), добавляет выравнивание, учитывает выравнивание подклассов и корректно работает с круговыми структурами данных и массивами. Вам просто нужно скомпилировать этот один .java файл; у него нет внешних зависимостей:

ObjectSizeCalculator.java

0

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

Проект jamm использует пакет java.lang.instrumentation, но проходит по дереву объектов и может предоставить глубокое использование памяти.

new MemoryMeter().measureDeep(myHashMap);

Подробности можно найти на GitHub.

Чтобы использовать MemoryMeter, запустите JVM с параметром "-javaagent:/jamm.jar".

0

Вы должны пройтись по объектам с помощью рефлексии. Будьте осторожны в этом процессе:

  • Просто выделение объекта создает некоторые накладные расходы в JVM. Размер этих расходов может варьироваться в зависимости от используемой JVM, поэтому имеет смысл сделать это значение параметром. По крайней мере, сделайте его константой (например, 8 байт) и применяйте к любому выделенному объекту.
  • Несмотря на то, что byte теоретически занимает 1 байт, в памяти он может занимать больше места.
  • В объектах могут быть циклические ссылки, поэтому вам нужно будет использовать HashMap или что-то подобное с использованием метода equals для сравнения объектов, чтобы избежать бесконечных циклов.

@jodonnell: Мне нравится простота вашего решения, но многие объекты не реализуют интерфейс Serializable (что приведет к выбросу исключения), поля могут быть временными, а объекты могут переопределять стандартные методы.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь