Как оценить размер сериализации объектов в Java без их сериализации?
Чтобы улучшить обмен сообщениями в кластере, важно знать во время выполнения о том, насколько велико сообщение (желательно ли мне обрабатывать локальный или удаленный).
Я мог бы просто найти фреймворки об оценке размера памяти объекта на основе Java-инструментария. Я тестировал classmexer, который не приближался к размеру сериализации и sourceforge SizeOf.
В маленькой тестовой папке SizeOf был около 10% ошибочным и в 10 раз быстрее, чем сериализация. (Тем не менее переходный режим полностью прерывает оценку, и, например, ArrayList является временным, но сериализуется как массив, не так легко исправлять параметр SizeOf. Но я мог бы жить с этим)
С другой стороны, 10 раз быстрее с ошибкой 10%, кажется, не очень хорошо. Любые идеи, как я мог бы сделать лучше?
Обновление: я также тестировал ObjectSize (http://sourceforge.net/projects/objectsize-java). Результаты кажутся просто хорошими для не наследуемых объектов: (
Ответы
Ответ 1
Размер, который занимает класс во время выполнения, не обязательно влияет на его размер в памяти. Пример, который вы упомянули, - это временные поля. Другие примеры включают, когда объекты реализуют Externalizable и сами обрабатывают сериализацию.
Если объект реализует Externalizable или предоставляет readObject()
/writeObject()
, то лучше всего сериализовать объект в буфер памяти, чтобы узнать размер. Это не будет быстро, но это будет точно.
Если объект использует сериализацию по умолчанию, вы можете изменить SizeOf, чтобы учесть переходные поля.
После сериализации многих из тех же типов объектов вы можете создать "профиль сериализации" для этого типа, который сопоставляет размер сериализованного размера и размер времени выполнения от SizeOf. Это позволит вам быстро оценить сериализованный размер (используя SizeOf), а затем сопоставить это с размером среды выполнения, чтобы получить более точный результат, чем тот, который предоставляется SizeOf.
Ответ 2
В других ответах есть много хороших моментов, одна недостающая - механизм сериализации может кэшировать определенные объекты.
Например, вы сериализуете серию объектов A, B и C всех тех же классов, которые содержат два объекта o1 и o2 в каждом объекте. Скажем, что служебные данные объекта составляют 100 байт, и, скажем, объекты выглядят так:
Object shared = new Object();
Object shread2 = new Object();
A.o1 = new Object()
A.o2 = shared
B.o1 = shared2
B.o2 = shared
C.o1 = shared2
C.o2 = shared
Для простоты можно сказать, что общие объекты берут 50 байтов для сериализации, а размер сериализации - 100 (служебные) + 50 (o1) + 50 (o2) = 200 байт. Можно было бы сделать аналогичную наивную оценку для B и C. Однако, если все три сериализованы одним и тем же потоком вывода объекта до того, как reset будет вызван тем, что вы увидите в потоке, это сериализация A и o1 и o2. Затем сериализация B и o1 для b, НО, а a ссылка на o2, поскольку это был тот же объект, который уже был сериализован. Поэтому давайте скажем, что ссылка на объект принимает 16 байтов, размер B теперь равен 100 (служебные) + 50 (o1) + 16 (ссылка для o2) = 166. Таким образом, размер, который требуется для сериализации, теперь изменился!
Мы могли бы выполнить вычисление simialr для C и получить 132 байта с двумя кэшированными объектами, поэтому размер сериализации для всех трех объектов различен с ~ 33% разницей между наибольшим и наименьшим.
Итак, если вы не сериализуете весь объект без кеша каждый раз, когда трудно точно оценить размер, необходимый для сериализации объекта.
Ответ 3
Просто идея: сначала вы можете сначала сериализовать объект в байтовый буфер, получить его длину и решить, следует ли отправлять содержимое буферов удаленному местоположению или выполнять локальную обработку (если это зависит от размера сообщений).
Недостаток - вы можете потратить время на сериализацию, если позже решите не использовать буфер. Но если вы оцениваете усилия по оценке отходов, если вам нужно сериализовать (потому что в этом случае вы сначала оцениваете и сериализуете на втором шаге).
Ответ 4
Невозможно оценить сериализованный размер объекта с хорошей точностью и скоростью. Например, какой-то объект может быть кешем цифр числа Pi, который строит себя во время выполнения с учетом только необходимой длины. Таким образом, он будет сериализовать только 4 байта атрибута length, в то время как объект может использовать сотни мегабайт памяти для хранения этого номера Pi.
Единственное решение, о котором я могу думать, это добавить свой собственный интерфейс, имея метод int estimateSerializeSize()
. Для каждого объекта, реализующего этот интерфейс, вам нужно будет вызвать этот метод, чтобы получить нужный размер. Если какой-то объект не реализует его, вам придется использовать SizeOf.