2009-03-02 5 views
5

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

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

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

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

ответ

6

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

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

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

+1

Я уже делал маршрут Externalizable в прошлом, и я получил увеличение производительности на 20-23% в сериализации/десериализации больших графов объектов. Объем работы, требуемый для этого, будет пропорционален количеству объектов, которые вы должны настроить. – Robin

+0

Просто проверьте http://code.google.com/p/fast-serialization/. Проблема решена :-) –

1

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

+0

Мне нужна улучшенная производительность при загрузке и хранении, но я не указал в этом вопросе, и действительно пространство также является мерой «производительности». –

+0

Меньше пространства означает, что меньше доступа к диску означает меньше времени –

+0

, только если процесс сериализации связан с диском.это, похоже, не в моей системе; это похоже на cpu-bound, поэтому сжатие просто замедлит его. –

1

Это, как я хотел бы сделать это, форма верхней части моей головы

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

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

Unserialization

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

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

+0

Это может сработать, но для этого потребуется переработать довольно некоторый код, который у меня есть –

+0

Как это было бы лучше, чем стандартная сериализация? Насколько я знаю, это уже сделано по умолчанию. –

+0

@saua, потому что вы можете лениво загружать и создавать экземпляр каждого объекта, когда это необходимо, вместо того, чтобы загружать его все сразу, вы также можете самостоятельно опуститься на уровень байта и оптимизировать формат сериализации. – thr

0

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

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

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

+0

В Кодо есть способ сделать это, но проблема в том, что это зависит от того, как объекты создаются в базе данных. К сожалению, база данных такова, что мы не можем этого сделать (и нет возможности изменить модель) –

10

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

+0

Это хорошее, общее важное соображение в любом случае. Я делаю это уже, но важно это упомянуть. +1 –

4

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

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

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

4

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

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

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

0

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

+0

Я уже пробовал, для этих типов объектов это еще хуже, чем Kodo. Сериализация Java быстрее, чем XStream. –

0

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

Смежные вопросы