- Default serialize – дефолтная сериализация java
- Serialize with methods – default сериализация с реализованными методами writeObject и readObject;
- Serialize with Externalize – еще один тип сериализации в java, реализующий интерфейс Externalize. Отличается от with methods только наличием пустого конструктора
- Custom serialize – наша «ручная сериализация», сами пишем поля без использования методов writeObject
Для сравнения разных видов сериализаци и десериализации был написан тест SerializerTest. Для наглядного представления результатов была реализована гистограмма на JavaFx:
- Тест проводился на
3_000_000объектовAnimal - Запуск тестов проводился не менее
5раз - Было проведено дополнительное тестирование без обработки null-ов при записи
- В таблицу занесены средние данные за последние
3запуска
| Type of serialize | Serialization time,ms |
Deserialization time,ms |
File size,bytes |
|---|---|---|---|
| Default | 48_883 | 73_607 | 61_689_892 |
| With methods | 61_054 | 64_392 | 64_443_996 |
| With externalize | 55_844 | 59_874 | 67_043_791 |
| Custom | 1_890 | 2_209 | 47_515_824 |
Стоит обратить внимание, что если в custom сериализации использовать DataStream вместо ObjectStream, получаем значительно уступающие показатели по времени у custom. В последних версиях Java была сильно оптимизирована JVM для использования ObjectStreams, поскольку это наиболее распространенный способ записи и чтения данных и, таким образом, находится на критическом пути производительности Java.
Приведем в качестве примера тест на DataStream с реализацией записи и чтения null:
| Type of serialize | Serialization time,ms |
Deserialization time,ms |
File size,bytes |
|---|---|---|---|
| Default | 47_461 | 73_641 | 61_501_387 |
| With methods | 60_527 | 63_979 | 64_867_855 |
| With externalize | 56_108 | 60_099 | 67_098_419 |
| Custom | 99_219 | 91_967 | 47_587_472 |
Как видно из результатов, custom работает значительно медленнее, при этом потерь по памяти нет.
Рассмотрим еще один пример, в котором будем использовать DataStream, но уже совместно с BufferedStream.
Для равных условий также добавим BufferedStream в другие реализации:
ObjectOutputStream oos = newObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(file)))иDataOutputStream oos = newDataOutputStream(new BufferedOutputStream(Files.newOutputStream(file)))
Аналогично и с Input. Получили такие результаты:
| Type of serialize | Serialization time,ms |
Deserialization time,ms |
File size,bytes |
|---|---|---|---|
| Default | 6_202 | 2_912 | 61_451_619 |
| With methods | 6_684 | 3_360 | 64_750_217 |
| With externalize | 5_169 | 2_592 | 67_033_558 |
| Custom | 1_807 | 1_958 | 47_538_602 |
Получили значительную оптимизацию по времени.
Будем везде испозьвать ObjectStream для default реализаций и DataStream совместно с BufferedStream для custom, поскольку в ручной сериализации предпочтительнее использовать DataStream.
Default показала лучшие результаты сериализации, чем with methods и externalizable, благодаря оптимизации, и при
этом худшие в десериализации из-за reflection.
Внутренний механизм Serializable во время работы генерирует большой объем служебной информации
и разного рода временных данных, предназначен для работы с любым объектом и может хранить данные,
которые не нужны для восстановления состояния объекта. В результате мы имеем большие по
сравнению с custom реализацией затраты по памяти и времени.
Serialize with methods и externalizable в сумме работают примерно также, как default.
Externalizable работает быстрее with methods, поскольку требует публичный конструктор без аргументов,
что позволяет экономить время на reflection. With methods и externalizable тратят
больше памяти, чем default, поскольку записывают метаинформацию о классах.
Custom сериализация показывает лучшие результаты как по времени, так и по памяти.
В данном виде сериализации записываются и считываются только строки и примитивные типы.
Нет необходимости сохранять большой объем служебной информации.
Получили аналогичные результаты, но уже с данными, имеющими больший размер.
Поскольку в тестах генерируется некоторое количество null объектов, которые не пишутся и, соответственно, не читаются, обход по всем элементам занимает меньше времени и памяти в случае обработки.
В процессе реализации serializer было замечено, что можно более эффективно записывать null и boolean,
теперь они ложатся в один байт.
