Pull to refresh

boolean — боремся за Java память…

Java *
У Вас когда-либо случались такие ситуации, когда Ваше Java приложение трещит по швам? В моём случае это случилось из-за нехватки доступной оперативной памяти. И, естественно, обнаружилась нехватка в самый неподходящий момент: на носу очередной долгожданный релиз, один из серверов остановлен для обновления кода и данных и реинкарнация старого кода уже невозможна, в ближайшие дни запланировано несколько совещаний и собеседований, что сильно отвлекает от процесса оптимизации — в общем, ЧП не прошло незамеченным.

К слову сказать, сделай я правильный backup и экстренные работы по восстановлению жизнеспособности прошли бы гораздо более спокойно, но это была бы уже совсем другая история. Итак в моём распоряжении есть код, которому не хватает 15Gb оперативной памяти для нормального функционирования и очень длительный и дорогостоящий процесс запуска (около 5 часов), в ходе работы которого можно только сидеть со скрещенными пальцами и надеятся, что в этот раз заветные слова OutOfMemoryException не появятся в консоли удалённого сервера.
Не буду описывать всех ухищрений, которые пришлось проделать, чтобы восстановить остановленный сервер в течении трёх дней, но одним своим мини открытием поделюсь — boolean — это не тот тип данных, который Вы хотите использовать в высоконагруженных системах. Внимание вопрос:

Как Вы думаете, сколько памяти занимает boolean например на Ubuntu server x64?

Правильным ответом будет: неизвестно и зависит только от реализации JVM.

Рассмотрим распространённую Sun JVM и прочтем в спецификации виртуальной машины, что boolean типа в ней нет как такового, вместо него используется int! А это означает, что для хранения значения типа «да\нет» используется ровно 32 бита, независимо от архитектуры процессора. Правда в том же разделе мы видим, что произведена оптимизация для работы с массивами boolean, которые преобразуются в массив байт, что даёт прирост доступной памяти в 4 раза. И всё же платить за хранение нолика или еденички семью лишними битами — иногда просто кощунство и издевательство над серверами (особенно при размерах массивов в 500 миллионов элементов).

Спасением в таких случаях будет класс BitSet, который ведёт себя подобно массиву boolean, но упаковывает данные так, что для одного бита выделяется всего один бит памяти (с небольшими издержками для всего массива). BitSet хранит внутри себя массив типа long, а при запросе или установке значения определенного бита — высчитывает индекс нужного long и пользуясь побитовыми операциями и операциями сдвига производит вычисления над единственным битом.
Существует еще более интересная реализация BitSet, OpenBitSet — Apache реализация, которая используется для Lucene. Она гораздо быстрее, но упускает некоторые проверки, проводимые в оригинальном BitSet. Что использовать — решать Вам.
Tags:
Hubs:
Total votes 108: ↑88 and ↓20 +68
Views 32K
Comments Comments 140