В Java, каков наилучший способ определить размер объекта?

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

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

Вы можете использовать пакет java.lang.instrument

Скомпилируйте и поместите этот class в JAR:

 import java.lang.instrument.Instrumentation; public class ObjectSizeFetcher { private static Instrumentation instrumentation; public static void premain(String args, Instrumentation inst) { instrumentation = inst; } public static long getObjectSize(Object o) { return instrumentation.getObjectSize(o); } } 

Добавьте в свой MANIFEST.MF :

 Premain-Class: ObjectSizeFetcher 

Использовать getObjectSize:

 public class C { private int x; private int y; public static void main(String [] args) { System.out.println(ObjectSizeFetcher.getObjectSize(new C())); } } 

Вызывать с:

 java -javaagent:ObjectSizeFetcherAgent.jar C 

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

Это всегда будет несколько менее точным, чем реализация на языке C просто из-за того, что происходит за кулисами classа, но это должен быть хороший индикатор.

В качестве альтернативы проект SourceForge соответствующим образом называется sizeof, который предлагает библиотеку Java5 с реализацией sizeof ().

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

Вы должны использовать jol , инструмент, разработанный как часть проекта OpenJDK.

JOL (Java Object Layout) – это крошечный инструментарий для анализа схем компоновки объектов в JVM. Эти инструменты используют Unsafe, JVMTI и Serviceability Agent (SA) в значительной степени для декодирования фактического макета объекта, следа и ссылок. Это делает JOL намного более точным, чем другие инструменты, основанные на кучих свалок, предположениях спецификации и т. Д.

Чтобы получить размеры примитивов, ссылок и элементов массива, используйте VMSupport.vmDetails() . В Oracle JDK 1.8.0_40, работающем на 64-битной Windows (используется для всех следующих примеров), этот метод возвращает

 Running 64-bit HotSpot VM. Using compressed oop with 0-bit shift. Using compressed klass with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 

Вы можете получить мелкий размер экземпляра объекта, используя ClassLayout.parseClass(Foo.class).toPrintable() (опционально передавая экземпляр toPrintable ). Это только пространство, потребляемое одним экземпляром этого classа; он не включает никаких других объектов, на которые ссылается этот class. Он включает в себя накладные расходы VM для заголовка объекта, выравнивания полей и заполнения. Для java.util.regex.Pattern :

 java.util.regex.Pattern object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000) 4 4 (object header) 00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000) 8 4 (object header) cb cf 00 20 (1100 1011 1100 1111 0000 0000 0010 0000) 12 4 int Pattern.flags 0 16 4 int Pattern.capturingGroupCount 1 20 4 int Pattern.localCount 0 24 4 int Pattern.cursor 48 28 4 int Pattern.patternLength 0 32 1 boolean Pattern.compiled true 33 1 boolean Pattern.hasSupplementary false 34 2 (alignment/padding gap) N/A 36 4 String Pattern.pattern (object) 40 4 String Pattern.normalizedPattern (object) 44 4 Node Pattern.root (object) 48 4 Node Pattern.matchRoot (object) 52 4 int[] Pattern.buffer null 56 4 Map Pattern.namedGroups null 60 4 GroupHead[] Pattern.groupNodes null 64 4 int[] Pattern.temp null 68 4 (loss due to the next object alignment) Instance size: 72 bytes (reported by Instrumentation API) Space losses: 2 bytes internal + 4 bytes external = 6 bytes total 

Вы можете получить сводный вид GraphLayout.parseInstance(obj).toFootprint() размера экземпляра объекта, используя GraphLayout.parseInstance(obj).toFootprint() . Конечно, некоторые объекты в области отпечатков могут быть разделены (также ссылаются на другие объекты), поэтому это чрезмерное приближение пространства, которое можно было бы вернуть, когда этот объект собирает мусор. Для результата Pattern.compile("^[a-zA-Z0-9_.+-][email protected][a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") (взято из этого ответа ), jol сообщает об общей глубине 1840 байт, из которых только 72 являются экземпляром Pattern.

 java.util.regex.Pattern instance footprint: COUNT AVG SUM DESCRIPTION 1 112 112 [C 3 272 816 [Z 1 24 24 java.lang.String 1 72 72 java.util.regex.Pattern 9 24 216 java.util.regex.Pattern$1 13 24 312 java.util.regex.Pattern$5 1 16 16 java.util.regex.Pattern$Begin 3 24 72 java.util.regex.Pattern$BitClass 3 32 96 java.util.regex.Pattern$Curly 1 24 24 java.util.regex.Pattern$Dollar 1 16 16 java.util.regex.Pattern$LastNode 1 16 16 java.util.regex.Pattern$Node 2 24 48 java.util.regex.Pattern$Single 40 1840 (total) 

Если вместо этого вы используете GraphLayout.parseInstance(obj).toPrintable() , jol сообщит вам адрес, размер, тип, значение и путь разметки полей для каждого объекта, на который ссылается, хотя обычно это слишком много деталей, чтобы быть полезным. Для текущего примера шаблонов вы можете получить следующее. (Адреса, вероятно, будут меняться между прогонами.)

 java.util.regex.Pattern object externals: ADDRESS SIZE TYPE PATH VALUE d5e5f290 16 java.util.regex.Pattern$Node .root.next.atom.next (object) d5e5f2a0 120 (something else) (somewhere else) (something else) d5e5f318 16 java.util.regex.Pattern$LastNode .root.next.next.next.next.next.next.next (object) d5e5f328 21664 (something else) (somewhere else) (something else) d5e647c8 24 java.lang.String .pattern (object) d5e647e0 112 [C .pattern.value [^, [, a, -, z, A, -, Z, 0, -, 9, _, ., +, -, ], +, @, [, a, -, z, A, -, Z, 0, -, 9, -, ], +, \, ., [, a, -, z, A, -, Z, 0, -, 9, -, ., ], +, $] d5e64850 448 (something else) (somewhere else) (something else) d5e64a10 72 java.util.regex.Pattern (object) d5e64a58 416 (something else) (somewhere else) (something else) d5e64bf8 16 java.util.regex.Pattern$Begin .root (object) d5e64c08 24 java.util.regex.Pattern$BitClass .root.next.atom.val$rhs (object) d5e64c20 272 [Z .root.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] d5e64d30 24 java.util.regex.Pattern$1 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object) d5e64d48 24 java.util.regex.Pattern$1 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object) d5e64d60 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object) d5e64d78 24 java.util.regex.Pattern$1 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object) d5e64d90 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object) d5e64da8 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs.val$lhs (object) d5e64dc0 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs (object) d5e64dd8 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs (object) d5e64df0 24 java.util.regex.Pattern$5 .root.next.atom (object) d5e64e08 32 java.util.regex.Pattern$Curly .root.next (object) d5e64e28 24 java.util.regex.Pattern$Single .root.next.next (object) d5e64e40 24 java.util.regex.Pattern$BitClass .root.next.next.next.atom.val$rhs (object) d5e64e58 272 [Z .root.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] d5e64f68 24 java.util.regex.Pattern$1 .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object) d5e64f80 24 java.util.regex.Pattern$1 .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object) d5e64f98 24 java.util.regex.Pattern$5 .root.next.next.next.atom.val$lhs.val$lhs (object) d5e64fb0 24 java.util.regex.Pattern$1 .root.next.next.next.atom.val$lhs.val$rhs (object) d5e64fc8 24 java.util.regex.Pattern$5 .root.next.next.next.atom.val$lhs (object) d5e64fe0 24 java.util.regex.Pattern$5 .root.next.next.next.atom (object) d5e64ff8 32 java.util.regex.Pattern$Curly .root.next.next.next (object) d5e65018 24 java.util.regex.Pattern$Single .root.next.next.next.next (object) d5e65030 24 java.util.regex.Pattern$BitClass .root.next.next.next.next.next.atom.val$rhs (object) d5e65048 272 [Z .root.next.next.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] d5e65158 24 java.util.regex.Pattern$1 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object) d5e65170 24 java.util.regex.Pattern$1 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object) d5e65188 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object) d5e651a0 24 java.util.regex.Pattern$1 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object) d5e651b8 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom.val$lhs.val$lhs (object) d5e651d0 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom.val$lhs (object) d5e651e8 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom (object) d5e65200 32 java.util.regex.Pattern$Curly .root.next.next.next.next.next (object) d5e65220 120 (something else) (somewhere else) (something else) d5e65298 24 java.util.regex.Pattern$Dollar .root.next.next.next.next.next.next (object) 

Записи «(что-то еще)» описывают другие объекты в куче, которые не являются частью этого графа объектов .

Лучшая jol-документация – это образцы jol в хранилище jol. Образцы демонстрируют общие операции jol и показывают, как вы можете использовать jol для анализа внутренних компонентов VM и сборщика мусора.

Во-первых, «размер объекта» не является четко определенной концепцией Java. Вы могли бы означать сам объект, с его членами, объектом и всеми объектами, на которые он ссылается (ссылочный граф). Вы можете указать размер в памяти или размер на диске. И JVM разрешено оптимизировать такие вещи, как Strings.

Поэтому единственный правильный способ – спросить JVM с хорошим профилировщиком (я использую YourKit ), который, вероятно, не тот, который вы хотите.

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

  Serializable ser; ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(ser); oos.close(); return baos.size(); 

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

Я случайно нашел java-class «jdk.nashorn.internal.ir.debug.ObjectSizeCalculator», уже находящийся в jdk, который прост в использовании и кажется весьма полезным для определения размера объекта.

 System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap(12000, 0.6f, -1))); System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap(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 

Если вы просто хотите узнать, сколько памяти используется в вашей JVM и сколько бесплатно, вы можете попробовать что-то вроде этого:

 // Get current size of heap in bytes long heapSize = Runtime.getRuntime().totalMemory(); // Get maximum size of heap in bytes. The heap cannot grow beyond this size. // Any attempt will result in an OutOfMemoryException. long heapMaxSize = Runtime.getRuntime().maxMemory(); // Get amount of free memory within the heap in bytes. This size will increase // after garbage collection and decrease as new objects are created. long heapFreeSize = Runtime.getRuntime().freeMemory(); 

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

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

https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java

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

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

 new MemoryMeter().measureDeep(myHashMap); 

https://github.com/jbellis/jamm

Вы должны пройти объекты, используя reflection. Будьте осторожны, как и вы:

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

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

Вы должны измерить его с помощью инструмента или оценить его вручную, и это зависит от используемой вами JVM.

Существует некоторая фиксированная накладная плата для каждого объекта. Это JVM-специфический, но я обычно оцениваю 40 байт. Затем вам нужно взглянуть на членов classа. Ссылки на объекты – это 4 (8) байта в 32-битной (64-разрядной) JVM. Примитивные типы:

  • boolean и byte: 1 байт
  • char и short: 2 байта
  • int и float: 4 байта
  • long и double: 8 байт

Массивы следуют тем же правилам; то есть это ссылка на объект, поэтому в вашем объекте требуется 4 (или 8) байта, а затем его длина умножается на размер ее элемента.

Попытка сделать это программно с помощью вызовов Runtime.freeMemory() просто не дает вам большой точности из-за асинхронных вызовов сборщику мусора и т. Д. Профилирование кучи с помощью -Xrunhprof или других инструментов даст вам наиболее точные результаты.

Я рекомендую библиотеку java-sizeof для поиска моркови. Это очень просто.

Вы можете получить его в maven:

   com.carrotsearch java-sizeof 0.0.3  

Только одна строка кода возвращает байты объекта:

 RamUsageEstimator.sizeOf(new Object()); 

Исходный код можно увидеть на странице https://github.com/dweiss/java-sizeof

И есть презентация от автора библиотеки http://www.slideshare.net/DawidWeiss/sizeofobject-how-much-memory-objects-take-on-jvms-and-when- this- may- matter? ref = HTTP: //cheremin.blogspot.com/2012/05/how-much-memory-objects-take-on-jvm-and.html

Класс java.lang.instrument.Instrumentation предоставляет хороший способ получить размер Java-объекта, но для этого требуется определить предварительную premain и запустить вашу программу с помощью java-агента. Это очень скучно, когда вам не нужен какой-либо агент, а затем вы должны предоставить фиктивный агент Jar для вашего приложения.

Поэтому я получил альтернативное решение, используя class Unsafe от sun.misc . Итак, учитывая выравнивание кучи объектов в соответствии с архитектурой процессора и вычисление максимального смещения поля, вы можете измерить размер объекта Java. В приведенном ниже примере я использую вспомогательный class UtilUnsafe для получения ссылки на объект sun.misc.Unsafe .

 private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model")); private static final int BYTE = 8; private static final int WORD = NR_BITS/BYTE; private static final int MIN_SIZE = 16; public static int sizeOf(Class src){ // // Get the instance fields of src class // List instanceFields = new LinkedList(); do{ if(src == Object.class) return MIN_SIZE; for (Field f : src.getDeclaredFields()) { if((f.getModifiers() & Modifier.STATIC) == 0){ instanceFields.add(f); } } src = src.getSuperclass(); }while(instanceFields.isEmpty()); // // Get the field with the maximum offset // long maxOffset = 0; for (Field f : instanceFields) { long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f); if(offset > maxOffset) maxOffset = offset; } return (((int)maxOffset/WORD) + 1)*WORD; } class UtilUnsafe { public static final sun.misc.Unsafe UNSAFE; static { Object theUnsafe = null; Exception exception = null; try { Class uc = Class.forName("sun.misc.Unsafe"); Field f = uc.getDeclaredField("theUnsafe"); f.setAccessible(true); theUnsafe = f.get(uc); } catch (Exception e) { exception = e; } UNSAFE = (sun.misc.Unsafe) theUnsafe; if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception); } private UtilUnsafe() { } } в private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model")); private static final int BYTE = 8; private static final int WORD = NR_BITS/BYTE; private static final int MIN_SIZE = 16; public static int sizeOf(Class src){ // // Get the instance fields of src class // List instanceFields = new LinkedList(); do{ if(src == Object.class) return MIN_SIZE; for (Field f : src.getDeclaredFields()) { if((f.getModifiers() & Modifier.STATIC) == 0){ instanceFields.add(f); } } src = src.getSuperclass(); }while(instanceFields.isEmpty()); // // Get the field with the maximum offset // long maxOffset = 0; for (Field f : instanceFields) { long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f); if(offset > maxOffset) maxOffset = offset; } return (((int)maxOffset/WORD) + 1)*WORD; } class UtilUnsafe { public static final sun.misc.Unsafe UNSAFE; static { Object theUnsafe = null; Exception exception = null; try { Class uc = Class.forName("sun.misc.Unsafe"); Field f = uc.getDeclaredField("theUnsafe"); f.setAccessible(true); theUnsafe = f.get(uc); } catch (Exception e) { exception = e; } UNSAFE = (sun.misc.Unsafe) theUnsafe; if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception); } private UtilUnsafe() { } } 

There is also the Memory Measurer tool (formerly at Google Code , now on GitHub ), which is simple and published under the commercial-friendly Apache 2.0 license , as discussed in a similar question .

It, too, requires a command-line argument to the java interpreter if you want to measure memory byte consumption, but otherwise seems to work just fine, at least in the scenarios I have used it.

Without having to mess with instrumentation and so on, and if you don’t need to know the byte-exact size of an object, you could go with the following approach:

 System.gc(); Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); do your job here System.gc(); Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 

This way you read the used memory before and after, and calling the GC just before getting the used memory you lower the “noise” almost to 0.

For a more reliable result you can run your job n times, and then divide the used memory by n, obtaining how much memory one run takes. Even more, you can run the whole thing more times and make an average.

I wrote a quick test once to estimate on the fly:

 public class Test1 { // non-static nested class Nested { } // static nested static class StaticNested { } static long getFreeMemory () { // waits for free memory measurement to stabilize long init = Runtime.getRuntime().freeMemory(), init2; int count = 0; do { System.out.println("waiting..." + init); System.gc(); try { Thread.sleep(250); } catch (Exception x) { } init2 = init; init = Runtime.getRuntime().freeMemory(); if (init == init2) ++ count; else count = 0; } while (count < 5); System.out.println("ok..." + init); return init; } Test1 () throws InterruptedException { Object[] s = new Object[10000]; Object[] n = new Object[10000]; Object[] t = new Object[10000]; long init = getFreeMemory(); //for (int j = 0; j < 10000; ++ j) // s[j] = new Separate(); long afters = getFreeMemory(); for (int j = 0; j < 10000; ++ j) n[j] = new Nested(); long aftersn = getFreeMemory(); for (int j = 0; j < 10000; ++ j) t[j] = new StaticNested(); long aftersnt = getFreeMemory(); System.out.println("separate: " + -(afters - init) + " each=" + -(afters - init) / 10000); System.out.println("nested: " + -(aftersn - afters) + " each=" + -(aftersn - afters) / 10000); System.out.println("static nested: " + -(aftersnt - aftersn) + " each=" + -(aftersnt - aftersn) / 10000); } public static void main (String[] args) throws InterruptedException { new Test1(); } } 

General concept is allocate objects and measure change in free heap space. The key being getFreeMemory() , which requests GC runs and waits for the reported free heap size to stabilize . The output of the above is:

 nested: 160000 each=16 static nested: 160000 each=16 

Which is what we expect, given alignment behavior and possible heap block header overhead.

The instrumentation method detailed in the accepted answer here the most accurate. The method I described is accurate but only under controlled conditions where no other threads are creating/discarding objects.

Here is a utility I made using some of the linked examples to handle 32-bit, 64-bit and 64-bit with compressed OOP. It uses sun.misc.Unsafe .

It uses Unsafe.addressSize() to get the size of a native pointer and Unsafe.arrayIndexScale( Object[].class ) for the size of a Java reference.

It uses the field offset of a known class to work out the base size of an object.

 import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.IdentityHashMap; import java.util.Stack; import sun.misc.Unsafe; /** Usage: * MemoryUtil.sizeOf( object ) * MemoryUtil.deepSizeOf( object ) * MemoryUtil.ADDRESS_MODE */ public class MemoryUtil { private MemoryUtil() { } public static enum AddressMode { /** Unknown address mode. Size calculations may be unreliable. */ UNKNOWN, /** 32-bit address mode using 32-bit references. */ MEM_32BIT, /** 64-bit address mode using 64-bit references. */ MEM_64BIT, /** 64-bit address mode using 32-bit compressed references. */ MEM_64BIT_COMPRESSED_OOPS } /** The detected runtime address mode. */ public static final AddressMode ADDRESS_MODE; private static final Unsafe UNSAFE; private static final long ADDRESS_SIZE; // The size in bytes of a native pointer: 4 for 32 bit, 8 for 64 bit private static final long REFERENCE_SIZE; // The size of a Java reference: 4 for 32 bit, 4 for 64 bit compressed oops, 8 for 64 bit private static final long OBJECT_BASE_SIZE; // The minimum size of an Object: 8 for 32 bit, 12 for 64 bit compressed oops, 16 for 64 bit private static final long OBJECT_ALIGNMENT = 8; /** Use the offset of a known field to determine the minimum size of an object. */ private static final Object HELPER_OBJECT = new Object() { byte b; }; static { try { // Use reflection to get a reference to the 'Unsafe' object. Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); UNSAFE = (Unsafe) f.get( null ); OBJECT_BASE_SIZE = UNSAFE.objectFieldOffset( HELPER_OBJECT.getClass().getDeclaredField( "b" ) ); ADDRESS_SIZE = UNSAFE.addressSize(); REFERENCE_SIZE = UNSAFE.arrayIndexScale( Object[].class ); if( ADDRESS_SIZE == 4 ) { ADDRESS_MODE = AddressMode.MEM_32BIT; } else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 8 ) { ADDRESS_MODE = AddressMode.MEM_64BIT; } else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 4 ) { ADDRESS_MODE = AddressMode.MEM_64BIT_COMPRESSED_OOPS; } else { ADDRESS_MODE = AddressMode.UNKNOWN; } } catch( Exception e ) { throw new Error( e ); } } /** Return the size of the object excluding any referenced objects. */ public static long shallowSizeOf( final Object object ) { Class objectClass = object.getClass(); if( objectClass.isArray() ) { // Array size is base offset + length * element size long size = UNSAFE.arrayBaseOffset( objectClass ) + UNSAFE.arrayIndexScale( objectClass ) * Array.getLength( object ); return padSize( size ); } else { // Object size is the largest field offset padded out to 8 bytes long size = OBJECT_BASE_SIZE; do { for( Field field : objectClass.getDeclaredFields() ) { if( (field.getModifiers() & Modifier.STATIC) == 0 ) { long offset = UNSAFE.objectFieldOffset( field ); if( offset >= size ) { size = offset + 1; // Field size is between 1 and PAD_SIZE bytes. Padding will round up to padding size. } } } objectClass = objectClass.getSuperclass(); } while( objectClass != null ); return padSize( size ); } } private static final long padSize( final long size ) { return (size + (OBJECT_ALIGNMENT - 1)) & ~(OBJECT_ALIGNMENT - 1); } /** Return the size of the object including any referenced objects. */ public static long deepSizeOf( final Object object ) { IdentityHashMap visited = new IdentityHashMap(); Stack stack = new Stack(); if( object != null ) stack.push( object ); long size = 0; while( !stack.isEmpty() ) { size += internalSizeOf( stack.pop(), stack, visited ); } return size; } private static long internalSizeOf( final Object object, final Stack stack, final IdentityHashMap visited ) { // Scan for object references and add to stack Class c = object.getClass(); if( c.isArray() && !c.getComponentType().isPrimitive() ) { // Add unseen array elements to stack for( int i = Array.getLength( object ) - 1; i >= 0; i-- ) { Object val = Array.get( object, i ); if( val != null && visited.put( val, val ) == null ) { stack.add( val ); } } } else { // Add unseen object references to the stack for( ; c != null; c = c.getSuperclass() ) { for( Field field : c.getDeclaredFields() ) { if( (field.getModifiers() & Modifier.STATIC) == 0 && !field.getType().isPrimitive() ) { field.setAccessible( true ); try { Object val = field.get( object ); if( val != null && visited.put( val, val ) == null ) { stack.add( val ); } } catch( IllegalArgumentException e ) { throw new RuntimeException( e ); } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } } } } } return shallowSizeOf( object ); } } 

Just use java visual VM.

It has everything you need to profile and debug memory problems.

It also has a OQL (Object Query Language) console which allows you to do many useful things, one of which being sizeof(o)

There isn’t a method call, if that’s what you’re asking for. With a little research, I suppose you could write your own. A particular instance has a fixed sized derived from the number of references and primitive values plus instance bookkeeping data. You would simply walk the object graph. The less varied the row types, the easier.

If that’s too slow or just more trouble than it’s worth, there’s always good old-fashioned row counting rule-of-thumbs.

You could generate a heap dump (with jmap, for example) and then analyze the output to find object sizes. This is an offline solution, but you can examine shallow and deep sizes, etc.

 long heapSizeBefore = Runtime.getRuntime().totalMemory(); // Code for object construction ... long heapSizeAfter = Runtime.getRuntime().totalMemory(); long size = heapSizeAfter - heapSizeBefore; 

size gives you the increase in memory usage of the jvm due to object creation and that typically is the size of the object.

My answer is based on the code supplied by Nick. That code measures total amount of bytes which are occupied by the serialized object. So this actually measures serialization stuff + plain object memory footprint (just serialize for example int and you will see that total amount of serialized bytes is not 4 ). So if you want to get raw byte number used exactly for your object – you need to modify that code a bit. Вот так:

 import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class ObjectSizeCalculator { private Object getFirstObjectReference(Object o) { String objectType = o.getClass().getTypeName(); if (objectType.substring(objectType.length()-2).equals("[]")) { try { if (objectType.equals("java.lang.Object[]")) return ((Object[])o)[0]; else if (objectType.equals("int[]")) return ((int[])o)[0]; else throw new RuntimeException("Not Implemented !"); } catch (IndexOutOfBoundsException e) { return null; } } return o; } public int getObjectSizeInBytes(Object o) { final String STRING_JAVA_TYPE_NAME = "java.lang.String"; if (o == null) return 0; String objectType = o.getClass().getTypeName(); boolean isArray = objectType.substring(objectType.length()-2).equals("[]"); Object objRef = getFirstObjectReference(o); if (objRef != null && !(objRef instanceof Serializable)) throw new RuntimeException("Object must be serializable for measuring it's memory footprint using this method !"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(o); oos.close(); byte[] bytes = baos.toByteArray(); for (int i = bytes.length - 1, j = 0; i != 0; i--, j++) { if (objectType != STRING_JAVA_TYPE_NAME) { if (bytes[i] == 112) if (isArray) return j - 4; else return j; } else { if (bytes[i] == 0) return j - 1; } } } catch (Exception e) { return -1; } return -1; } } 

I’ve tested this solution with primitive types, String, and on some trivial classes. There may be not covered cases also.

UPDATE: Example modified to support memory footprint calculation of array objects.

This answer is not related to Object size, but when you are using array to accommodate the objects; how much memory size it will allocate for the object.

So arrays, list, or map all those collection won’t be going to store objects really (only at the time of primitives, real object memory size is needed), it will store only references for those objects.

Now the Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

  • (4/8 bytes) depends on (32/64 bit) OS

PRIMITIVES

 int [] intArray = new int [1]; will require 4 bytes. long [] longArray = new long [1]; will require 8 bytes. 

OBJECTS

 Object[] objectArray = new Object[1]; will require 4 bytes. The object can be any user defined Object. Long [] longArray = new Long [1]; will require 4 bytes. 

I mean to say all the object REFERENCE needs only 4 bytes of memory. It may be String reference OR Double object reference, But depends on object creation the memory needed will vary.

eg) If i create object for the below class ReferenceMemoryTest then 4 + 4 + 4 = 12 bytes of memory will be created. The memory may differ when you are trying to initialize the references.

  class ReferenceMemoryTest { public String refStr; public Object refObj; public Double refDoub; } 

So when are creating object/reference array, all its contents will be occupied with NULL references. And we know each reference requires 4 bytes.

And finally, memory allocation for the below code is 20 bytes.

ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); ( 4(ref1) + 12 = 16 bytes) ReferenceMemoryTest ref2 = ref1; ( 4(ref2) + 16 = 20 bytes)

For JSONObject the below code can help you.

 `JSONObject.toString().getBytes("UTF-8").length` 

returns size in bytes

I checked it with my JSONArray object by writing it to a file. It is giving object size.

I doubt you want to do it programmatically unless you just want to do it once and store it for future use. It’s a costly thing to do. There’s no sizeof() operator in Java, and even if there was, it would only count the cost of the references to other objects and the size of the primitives.

One way you could do it is to serialize the thing to a File and look at the size of the file, like this:

 Serializable myObject; ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("obj.ser")); oos.write (myObject); oos.close (); 

Of course, this assumes that each object is distinct and doesn’t contain non-transient references to anything else.

Another strategy would be to take each object and examine its members by reflection and add up the sizes (boolean & byte = 1 byte, short & char = 2 bytes, etc.), working your way down the membership hierarchy. But that’s tedious and expensive and ends up doing the same thing the serialization strategy would do.

  • Использование памяти в C #
  • Что такое PermSize в Java?
  • Создание утечки памяти с помощью Java
  • AngularJS - $ destroy удаляет прослушиватели событий?
  • Использование Java ReferenceQueue
  • Общая страtagsя для устранения утечки памяти Java?
  • Какие страtagsи и инструменты полезны для обнаружения утечек памяти в .NET?
  • Невозможно освободить память, занятую байтами.
  • По умолчанию Xmxsize в Java 8
  • Как определить размер моего массива в C?
  • Как найти утечку памяти Java
  • Давайте будем гением компьютера.