Почему важно знать как работает память в Java

Java Tech Talks Odessa

Очередная статья из самолета. В этот раз я возвращаюсь из Одессы, где выступал на Java Tech Talks #5, организованном компанией Lohika. Принимали нас очень тепло: позаботились о приезде, надарили подарков, назадавали интересных вопросов. Тема моего выступления касалась тонкостей и неприятностей работы с Hibernate. Я полтора часа “мучил” людей своими жалобами и советами по использованию Hibernate, ORM в целом и особенностей применения в разных условиях. Но статья не об этом. Презентацию моего выступления можно глянуть тут:

Следом за мной выступал Дима Думанский с докладом на тему использования памяти в Java. Доклад очень полезен тем, кто не имеет представления или никогда не задумывался на тему сколько места в памяти занимает тот или иной объект. Многие скажут: “Да нам это не особо и интересно! Что ж нам объекты не создавать, зная что много памяти будет использовано?”. Я приведу пару примеров, которые продемонстрируют полезность такого рода знаний.

Первый пример относится к справочникам. Это могут быть любые справочники – адреса, телефоны, имена, фамилии, коды товаров и т.д. Конечно, вы хотели бы хранить их в памяти для максимально быстрого доступа. Поэтому при старте системы вычитываете справочники из базы данных, файловой системы или другого хранилища. И тут вас ждет небольшой “сюрприз”. Все знают, что внутри объект строка представлен массивом символов, который аккуратно обернут в класс String. И оказывается, что JVM для каждого экземпляра этого класса хранит служебную информацию, которая по размеру занимает 40 байт. 

И что с этого? А то, что при коротких значениях справочника этот размер в разы превышает размер самих данных. Поэтому при размере справочника на диске 100MB в памяти он начинает занимать 500-800MB, а может и того больше… Согласитесь, что это не лучшее использование памяти. Выход есть – для подобных задач применяются деревья и прочие специальные структуры, которые позволяют сохранять строковые значения в гораздо более компактном виде.

Второй пример связан с библиотекой для разбора XML и преобразования его в дерево объектов – commons digester. Это очень простое решение для многих случаев. Вы просто объявляете карту соответствия тэгов с вашими классами и вуаля – на выходе готовое к использованию дерево объектов. Библиотека отлично подходит для разбора конфигураций, ответов от различных сервисов и прочих задач.

Каково же было наше удивление, когда на больших XML решение начинало “пожирать” очень много памяти и работать чрезвычайно медленно. Внутри используется простой SAX парсер, что может пойти не так? После изнурительной работы с профилировщиками выяснилось, что проблема кроется в логировании. Digester все свои действия логирует, добавляя информацию о текущем состоянии и процессе обработки. Естественно на уровне DEBUG. Но при этом строки сообщений логирования создаются даже при отключенном уровне DEBUG. А мы знаем, что создание новых строк – дорогая операция как по времени так и по памяти. Ко всему прочему, очень скоро присоединяется сборщик мусора и ваше приложение начинает “задыхаться”. 🙂

Так что, даже если вы и не планируете заниматься отладкой и тюнингом использования памяти как некоторые большие проекты наподобие Twitter и Одноклассники, тем не менее важно разбираться в базовых принципах и правилах. Тогда вы сможете работать гораздо спокойнее и не переживать за судьбу вашего приложения.

Не хочешь пропускать ничего интересного? Подпишись на ленту RSS или следи за нами в Twitter!

Обсуждение (0)

Leave a Reply

Your email address will not be published. Required fields are marked *