2013-03-19 2 views
8

Я пытаюсь понять, каков объем памяти объекта на Java. Я прочитал this и другие документы об объекте и памяти на Java.Объект памяти объекта Java - измерение Visualvm и java.sizeOf

Однако, когда я использую sizeof Java library или visualvm, я получаю два разных результата, в которых ни одна из них не может быть ожидаемой в соответствии с предыдущей ссылкой (http://www.javamex.com).

Для моего теста я использую Java SE 7 Developer Preview на 64-bits Mac с java.sizeof 0.2.1 и visualvm 1.3.5.

У меня есть три класса, TestObject, TestObject2, TestObject3.

public class TestObject 
{ 

} 

public class TestObject2 extends TestObject 
{ 
    int a = 3; 
} 

public class TestObject3 extends TestObject2 
{ 
    int b = 4; 
    int c = 5; 
} 

Мой главный класс:

public class memoryTester 
{ 
    public static void main(String[] args) throws Throwable 
    { 
     TestObject object1 = new TestObject(); 
     TestObject2 object2 = new TestObject2(); 
     TestObject3 object3 = new TestObject3(); 

     int sum = object2.a + object3.b + object3.c; 
     System.out.println(sum); 

     SizeOf.turnOnDebug(); 

     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object1))); 
     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object2))); 
     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object3))); 
    } 
} 

С java.SizeOf() я получаю:

{ test.TestObject 
} size = 16.0b 
16.0b 

{ test.TestObject2 
a = 3 
} size = 16.0b 
16.0b 

{ test.TestObject3 
b = 4 
c = 5 
} size = 24.0b 
24.0b 

С VisualVM у меня есть:

this (Java frame) TestObject #1 16 
this (Java frame) TestObject2 #1 20 
this (Java frame) TestObject3 #1 28 

Согласно документаций I читать через Интернет, поскольку я в 64-битных, я должен имеют заголовок объекта 16 байт, ok для TestObject.

Затем для TestObject2 Я должен добавить 4 байта для целочисленного поля, дающего 20 байтов, я должен добавить еще 4 байта заполнения, давая общий размер 24 байта для TestObject2. Я ошибаюсь?

Продолжая этот путь для TestObject3, я должен добавить еще 8 байтов для двух целых полей, которые должны дать 32 байта.

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

Вопросы:

Почему эти два инструмента дают разные результаты?

Должны ли мы иметь прокладку?

Я также где-то читал (я не нашел ссылку), что между классом и его подклассом может быть какое-то дополнение, верно? В этом случае унаследованное дерево классов может иметь некоторые издержки памяти?

И, наконец, есть ли какой-либо Java spec/doc, который детализирует, что делает Java?

Благодарим за помощь.

Update:

Чтобы ответить на комментарий от utapyngo, чтобы получить размер объектов в VisualVM, я создаю heapdump, а затем в «классах» часть I в столбце «размер» следующий после столбец «экземпляры». Количество экземпляров, если 1 для каждого типа объектов.

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

+0

У нас нет способа узнать, что правильно, если они не видят своей логики, как они измеряют потребление памяти. –

+0

В моем случае jvisualvm 1.7.0 (Build 110325) на 64-битной Java 1.7.0-b147 дает 16, 16 и 24. Какой метод вы используете для измерения с помощью visualvm? – utapyngo

+0

Возможно, вам не удастся получить точные результаты без присвоения значения полям-членам 'a',' b' и 'c'. В основе реализации JVM может не потребоваться фактическое выделение памяти для не используемых полей, а выделение памяти для хранения указателей на эти поля. –

ответ

2

Да дополнение может случиться. Также возможно, чтобы объекты в стеке полностью оптимизировались. Только JVM знает точные размеры в любой момент времени. Поскольку такие методы, чтобы приблизиться к размеру из языка Java, все имеют тенденцию не соглашаться, инструменты, которые прикрепляются к JVM, как правило, являются наиболее точными. Три основные методы реализации SIZEOF в Java, что я знаю, являются:

  1. сериализации объекта и возвращает длину этих байтов (явно не так, но полезно для относительных сравнений)
  2. Список отражения элемента, и константы жесткого кодирования для каждого поля, найденного на объекте. можно настроить , чтобы быть точным, но изменения в JVM и дополнении , которые JVM может или не может сделать, это бросить его.
  3. Элемент списка создания нагрузки объектов, запустить дс и сравнить изменения в Jvm размер кучи

Ни один из этих методов не являются точными.

Если вы работаете на JVM Oracle, то или после версии 1.5. Затем есть способ прочитать размер объекта прямо из структуры C, используемой средой выполнения Java. Не очень хорошая идея для производства, и вы ошибаетесь, вы можете разрушить JVM. Но вот сообщение в блоге, которое может показаться вам интересным, если вы хотите по нему поработать: http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/

Что касается документации о том, что на самом деле делает Java, то это специфичная для JVM, специфичная для конкретной версии и потенциально конфигурируемая. Каждая реализация может свободно обрабатывать объекты по-разному. Даже в том случае, если цели полностью исключены, например, объекты, которые не удаляются из стека, не могут быть выделены в кучу. Некоторые JVM могут даже полностью сохранить объект в реестре CPU. Не ваш случай здесь, но я включаю его в качестве примера, почему получение истинного размера объектов Java является сложным.

Так что лучше всего использовать любые значения размера, которые вы получаете с щепоткой соли и относитесь к нему только как «ориентировочное» измерение.

+0

Я бы добавил еще одну точку для измерения размера объекта: с помощью пакета Instrument и метода getObjectSize(). Как написано в java-документе, он возвращает только оценочный размер объекта. Но я думаю, что это то, что вы хотели сказать, «инструменты, которые прикрепляются к JVM, как правило, являются наиболее точными». Я проверил, что делает библиотека java.sizeof, и кажется, что они правильно используют метод getObjectSize().Я ожидаю, что visualvm сделает то же самое. Поэтому, если оба инструмента используют инструмент Java, остается вопрос, почему разные результаты? Наверное, мне нужно отправить письмо команде visulvm. –