Советы по производительности для сериализации объектов Java - PullRequest
5 голосов
/ 02 марта 2009

Я должен сериализовать огромное дерево объектов (7 000) в диск. Первоначально мы хранили это дерево в базе данных с помощью Kodo, но для загрузки этого дерева в память потребовалось бы тысячи и тысячи запросов, и это заняло бы значительную часть доступного времени локальной вселенной.

Я попробовал сериализацию для этого и действительно получаю улучшение производительности. Однако у меня возникает ощущение, что я могу улучшить это, написав свой собственный код сериализации. Мне нужно как можно быстрее загрузить этот сериализованный объект.

На моей машине сериализация / десериализация этих объектов занимает около 15 секунд. При загрузке их из базы данных это занимает около 40 секунд.

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

Ответы [ 9 ]

10 голосов
/ 02 марта 2009

Не забудьте использовать ключевое слово 'transient' для переменных экземпляра, которые не нужно сериализовать. Это дает вам повышение производительности, потому что вы больше не читаете / пишете ненужные данные.

6 голосов
/ 02 марта 2009

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

Создание классов Externalizable вместо Serializable может дать некоторые преимущества в производительности. Недостатком является то, что это требует много ручной работы.

Затем существуют другие библиотеки сериализации, например, jserial , которые могут обеспечить более высокую производительность, чем сериализация по умолчанию в Java. Кроме того, если граф объектов не включает циклы, то его можно сериализовать немного быстрее, поскольку сериализатору не нужно отслеживать объекты, которые он видел (см. «Как это работает?» В FAQ по jserial). ).

4 голосов
/ 02 марта 2009

Чтобы избежать необходимости писать собственный код сериализации, попробуйте Буферы протокола Google . По данным их сайта:

Буферы протокола - это независимый от языка, платформенно-независимый, расширяемый механизм Google для сериализации структурированных данных - думайте XML, но меньше, быстрее и проще. Вы определяете, как вы хотите, чтобы ваши данные были структурированы один раз, затем вы можете использовать специальный сгенерированный исходный код, чтобы легко записывать и считывать ваши структурированные данные в различные потоки данных и из них, используя различные языки - Java, C ++ или Python

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

4 голосов
/ 02 марта 2009

Я бы рекомендовал вам реализовать собственные методы writeObject () и readObject () . Таким образом, вы сможете записывать записи для всех узлов в дереве. Когда вы используете сериализацию по умолчанию, каждый узел будет сериализован со всеми его дочерними элементами.

Например, writeObject () класса Tree должен выполнять итерацию по всем узлам дерева и записывать только данные узлов (без самих узлов) с некоторыми маркерами, которые идентифицируют Уровень дерева.

Вы можете посмотреть LinkedList , чтобы увидеть, как эти методы реализованы там. Он использует тот же подход, чтобы предотвратить запись записей prev и next для каждой отдельной записи.

1 голос
/ 02 марта 2009

Вот как бы я это сделал, сформировав макушку моей головы

Сериализация

  1. Сериализация каждого объекта в отдельности
  2. Назначьте каждому объекту уникальный ключ
  3. Когда объект содержит ссылку на другой объект, поместите уникальный ключ для этого объекта в место объектов в сериализации. (Я бы использовал UUID, преобразованный в двоичный файл)
  4. Сохранение каждого объекта в файл / базу данных / хранилище с использованием уникального ключа

Unserialization

  1. Начать с произвольного объекта (обычно я подозреваю, что это корень), десериализовать его, поместить в карту с уникальным ключом в качестве индекса и вернуть его
  2. Когда вы нажимаете на объектный ключ в потоке сериализации, сначала проверяет, является ли он уже не сериализованным , ища его уникальный ключ на карте и просто берет его оттуда, если нет Ленивая загрузка прокси-сервера (который повторяет эти два шага для этого объекта) вместо реального объекта, у которого есть хуки для загрузки нужного объекта, когда он вам нужен.

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

1 голос
/ 02 марта 2009

Вы пытались сжать поток (GZIPOutputStream)?

0 голосов
/ 09 апреля 2017

Вы можете использовать Colfer для генерации bean-компонентов, и стандартная производительность сериализации Java увеличится в 10 - 1000 раз. Если размер не превысит ГБ, скорее всего, вы будете намного ниже секунды.

0 голосов
/ 02 марта 2009

Также взгляните на XStream , библиотеку для сериализации объектов в XML и обратно.

0 голосов
/ 02 марта 2009

Для производительности я бы предложил вообще не использовать сериализацию java.io. Вместо этого сами приступайте к байту.

Если вы собираетесь сериализовать дерево в java.io, вам может потребоваться убедиться, что ваша рекурсия не становится слишком глубокой, либо путем сглаживания (как, скажем, TreeSet), либо путем организации сначала сериализации самых глубоких узлов (так у вас есть обратные ссылки, а не вложенные readObject вызовы).

Я был бы удивлен, если бы в Кодо не было способа прочитать все дерево за один (или несколько) раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...