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

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

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

24 ответов


можно использовать java.ленг.пакет инструментов

скомпилируйте и поместите этот класс В банку:

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()));
    }
}

Invoke with:

java -javaagent:ObjectSizeFetcherAgent.jar C

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

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

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

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


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

JOL (Java Object Layout) - это крошечный набор инструментов для анализа схем компоновки объектов в JVMs. Эти инструменты используют 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). Это только пространство, потребляемое одним экземпляром этого класса; оно не включает никаких других объектов, на которые ссылается этот класс. Это тут включить накладные расходы виртуальной машины для заголовка объекта, выравнивания полей и заполнения. Для 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(). Конечно, некоторые объекты в footprint могут быть общими (также ссылаются на другие объекты), поэтому это чрезмерное сокращение пространства, которое может быть восстановлено, когда этот объект собирает мусор. За результат Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$") (взято из ответ), JOL сообщает полный след ноги 1840 байт, из которых только 72 являются экземпляром шаблона.

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
        13        24       312   java.util.regex.Pattern
         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        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d48         24 java.util.regex.Pattern        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d60         24 java.util.regex.Pattern        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d78         24 java.util.regex.Pattern        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d90         24 java.util.regex.Pattern        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64da8         24 java.util.regex.Pattern        .root.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64dc0         24 java.util.regex.Pattern        .root.next.atom.val$lhs.val$lhs (object)
         d5e64dd8         24 java.util.regex.Pattern        .root.next.atom.val$lhs        (object)
         d5e64df0         24 java.util.regex.Pattern        .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        .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64f80         24 java.util.regex.Pattern        .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e64f98         24 java.util.regex.Pattern        .root.next.next.next.atom.val$lhs.val$lhs (object)
         d5e64fb0         24 java.util.regex.Pattern        .root.next.next.next.atom.val$lhs.val$rhs (object)
         d5e64fc8         24 java.util.regex.Pattern        .root.next.next.next.atom.val$lhs (object)
         d5e64fe0         24 java.util.regex.Pattern        .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        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e65170         24 java.util.regex.Pattern        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e65188         24 java.util.regex.Pattern        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e651a0         24 java.util.regex.Pattern        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e651b8         24 java.util.regex.Pattern        .root.next.next.next.next.next.atom.val$lhs.val$lhs (object)
         d5e651d0         24 java.util.regex.Pattern        .root.next.next.next.next.next.atom.val$lhs (object)
         d5e651e8         24 java.util.regex.Pattern        .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 для анализа внутренних компонентов VM и сборщика мусора.


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

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


я случайно нашел класс java "jdk.нэшорн.внутренний.ИК.отладка.ObjectSizeCalculator", уже в jdk, который прост в использовании и кажется довольно полезным для определения размера объекта.

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

Если вы просто хотите знать, сколько памяти используется в вашей 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-разрядные), заполнение, подкласс, корректно работает на круговых структурах данных и массивах. Вы можете просто скомпилировать это .java-файл; он не имеет внешних зависимостей:

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


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

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

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm


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

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

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


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

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

  • boolean и Байт: 1 байт
  • char и короткий: 2 байт
  • int и float: 4 байты
  • длинный и двойной: 8 байт

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

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


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

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

 <dependency>
    <groupId>com.carrotsearch</groupId>
    <artifactId>java-sizeof</artifactId>
    <version>0.0.3</version>
</dependency>

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

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 для вашего приложения.

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


есть еще Замерщик Памяти (ранее по Код Google, сейчас на GitHub), который прост и опубликован под коммерчески-содружественным Лицензия Apache 2.0, Как обсуждалось в аналогичный вопрос.

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


вот утилита, которую я сделал, используя некоторые из связанных примеров для обработки 32-бит, 64-бит и 64-бит со сжатым ООП. Он использует sun.misc.Unsafe.

Он использует Unsafe.addressSize() чтобы получить размер собственного указателя и Unsafe.arrayIndexScale( Object[].class ) для размера ссылки Java.

он использует смещение поля известного класса для определения базового размера объекта.

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<Object,Object> visited = new IdentityHashMap<Object,Object>();
        Stack<Object> stack = new Stack<Object>();
        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<Object> stack, final IdentityHashMap<Object,Object> 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 );
    }
}

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

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

do your job here

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

таким образом, Вы читаете используемую память до и после и вызываете GC непосредственно перед получением используемой памяти, вы понижаете "шум" почти до 0.

для более надежного результата вы можете запустить задание n раз, а затем разделить используемую память на n, получив, сколько памяти занимает один запуск. Даже более того, вы можете запустить все это дело еще раз и в среднем.


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

Если это слишком медленно или просто больше проблем, чем стоит, всегда есть хорошее старомодное правило подсчета строк.


Я написал быстрый тест один раз, чтобы оценить на лету:

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();
    }

}

общая концепция заключается в выделении объектов и изменении меры в свободном пространстве кучи. КлючgetFreeMemory(), который запросы GC запускается и ждет, пока сообщенный свободный размер кучи стабилизируется. Вывод из вышеизложенного:

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

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

метод инструментирования, подробно описанный в принятой ответ здесь самый точный. Метод, который я описал, является точным, но только в контролируемых условиях, когда никакие другие потоки не создают/отбрасывают объекты.


просто используйте Java visual VM.

в нем есть все необходимое для профилирования и отладки проблем с памятью.

Он также имеет консоль Oql (Object Query Language), которая позволяет вам делать много полезных вещей, одна из которых sizeof(o)


вы можете создать дамп кучи (например, с помощью jmap), а затем проанализировать выходные данные, чтобы найти размеры объектов. Это автономное решение, но вы можете исследовать мелкие и глубокие размеры и т. д.


long heapSizeBefore = Runtime.getRuntime().totalMemory();

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

size дает вам увеличение использования памяти jvm из-за создания объекта, и обычно это размер объекта.


мой ответ основан на коде, предоставленном ником. Этот код измеряет общее количество байтов, занятых сериализованным объектом. Таким образом, это фактически измеряет материал сериализации + простой объем памяти объекта (просто сериализуйте, например int и вы увидите, что общий объем сериализованных данных не 4). Поэтому, если вы хотите получить сырой номер байта, используемый именно для вашего объекта - вам нужно немного изменить этот код. Вот так:

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;
    }    

}

Я проверил это решение с примитивными типами, строкой и некоторыми тривиальными классами. Могут также не охватываться случаи.


обновление: пример изменен для поддержки вычисления объема памяти объектов массива.


этот ответ не связан с размером объекта, но когда вы используете массив для размещения объектов; сколько памяти он выделит для объекта.

таким образом, массивы, список или карта все эти коллекции не будут хранить объекты на самом деле (только во время примитивов требуется реальный размер памяти объекта), он будет хранить только ссылки для этих объектов.

теперь Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

  • (4/8 байт) зависит от (32/64 бит) OS

примитивы

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

объекты

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.

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

e.g) если я создаю объект для приведенного ниже класса ReferenceMemoryTest тогда 4 + 4 + 4 = будет создано 12 байт памяти. Память может отличаться, когда вы пытаетесь инициализации ссылки.

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

поэтому при создании массива объектов / ссылок все его содержимое будет занято нулевыми ссылками. И мы знаем, что каждая ссылка требует 4 байта.

и, наконец, выделение памяти для приведенного ниже кода составляет 20 байт.

ReferenceMemoryTest ref1 = новый ReferenceMemoryTest (); (4 (ref1) + 12 = 16 байт) ReferenceMemoryTest ref2 = ref1; (4 (ref2) + 16 = 20 байт)


для JSONObject приведенный ниже код может вам помочь.

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

возвращает размер в байтах

Я проверил его с помощью объекта JSONArray, записав его в файл. Это дает размер объекта.


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

один из способов сделать это-сериализовать вещь в файл и посмотреть на размер файла, например:

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

конечно, это предполагает, что каждый объект distinct и не содержит нестационарных ссылок ни на что другое.

другой стратегией было бы взять каждый объект и изучить его члены путем отражения и сложить размеры (boolean & byte = 1 байт, short & char = 2 байта и т. д.), прокладывая свой путь вниз по иерархии членства. Но это утомительно и дорого и в конечном итоге делает то же самое, что и стратегия сериализации.