В Java, каков наилучший способ определить размер объекта?
например, предположим, у меня есть приложение, которое может читать в CSV-файле с грудами строк данных. Я даю пользователю сводку о количестве строк на основе типов данных, но я хочу убедиться, что я не читаю слишком много строк данных и не вызываю OutOfMemoryError
s. Каждая строка преобразуется в объект. Есть простой способ узнать размер этого объекта программно? Есть ли ссылка, которая определяет, насколько велики примитивные типы и ссылки на объекты для 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-файл; он не имеет внешних зависимостей:
многие другие ответы предоставляют небольшие размеры-например, размер хэш-карты без каких-либо ключей или значений, что вряд ли вам нужно.
проект jamm использует java.ленг.пакет инструментов выше, но ходит по дереву и поэтому может дать вам глубокое использование памяти.
new MemoryMeter().measureDeep(myHashMap);
вы должны ходить по объектам, используя отражение. Будьте осторожны, как вы делаете:
- просто выделение объекта имеет некоторые накладные расходы в 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 байта и т. д.), прокладывая свой путь вниз по иерархии членства. Но это утомительно и дорого и в конечном итоге делает то же самое, что и стратегия сериализации.