CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-приложениях
1. Управление памятью в Java:
footprint
Владимир Иванов
Oracle Corp.
vladimir.x.ivanov@oracle.com
1
2. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
2
3. Введение
О чем пойдет речь?
• Производительность GC
• 3 характеристики
• Throughput
• Объем вычислительных ресурсов, затрачиваемых на GC
• Предсказуемость
• На какое время прерывается работа приложения
• Footprint
• Объем используемой памяти
3
4. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
4
6. Критерии выбора размера «кучи»
• Чем больше памяти, тем лучше для GC
• Как для молодого, так и для старшего поколения
• Более редкие сборки
• Ниже затраты на сборку мусора
• Доступный объем памяти ограничен
• Физическая память
• 32-битный режим
• Наличие других приложений в системе
6
7. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
7
8. «Сжатые» указатели
-XX:+UseCompressedOops
• 32-битные указатели в 64-битном режиме
• oop - Ordinary Object Pointer
Размер < 4Gb >= 4Gb >= 26Gb
«кучи» < 26Gb < 32Gb
Режим Zero-based Zero-based Offset-based
работы non-aligned 8-byte aligned 8-byte aligned
Декоди- не требуется x << 3 offset + x << 3
рование
8
9. «Сжатые» указатели
-XX:+UseCompressedOops
• Распаковка «сжатых» указателей дешева
– 64-bit JVM + zero-based COOPs быстрее 32-bit JVM
– 64-bit JVM + offset-based COOPs немного медленнее 64-bit
JVM + zero-based COOPs
• 1 регистр используется для хранения offset
• Работают для «кучи» размером не более 32Gb
• ~1.4x увеличение размера данных если выключены
• скачок: 32Gb -> 45Gb
9
10. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
10
11. Представление объекта в памяти
• Заголовок (12/16/20 байт)
– mark word (4/8 байт)
– указатель на класс объекта (4/8 байт)
– длина (только для массива) (4 байта)
• Нестатические поля класса / элементы массива
– эффективное представление
– выбор оптимального порядка
– порядок полей
• long/double, int, short/char, byte/boolean, reference
• http://github.com/shipilev/java-object-layout
• -XX:+PrintCompactFieldsSavings
11
12. Представление объекта в памяти
• new int[1000] • new Integer[1000]
• 32-бита: 4+4+4+1000*4 = • 32-бита: 4+4+4+1000*(4+4+4+4) =
4012 байт 16012 байт
• 64-бита: 8+8+4+1000*4 = • 64-бита: 8+8+4+1000*(8+8+8+4) =
4020 байт 28020 байт
12
13. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
13
14. Инженерная проблема
Кэширование данных
• Приложение оперирует объемами данных,
существенно превышающими доступную память
• Требуется организовать кэширование на уровне
приложения
14
15. Типы ссылок в Java
• Декларативный API к GC
• Контроль достижимости
• Представлены в виде объектов
• extends java.lang.ref.Reference
• 3 типа
• «мягкие»
• java.lang.ref.SoftReference
• «слабые»
• java.lang.ref.WeakReference
• «фантомные»
• java.lang.ref.PhantomReference
15
16. Типы ссылок в Java
Как использовать?
import java.lang.ref.*;
Object obj = new Object(); // strong reference
Reference softRef = new SoftReference(obj); // soft reference
Reference weakRef = new WeakReference(obj); // weak reference
// phantom reference
ReferenceQueue reqQueue = new ReferenceQueue(obj);
Reference phantomRef = new PhantomReference(obj, refQueue);
Object obj1 = softRef.get(); if (obj1 != null) { … }
16
18. Типы ссылок
SoftReference
• Удаление softly reachable объекта при нехватке
памяти в системе
• Гарантии
• Все «мягкие» ссылки к soft-достижимым объектам будут
очищены до того, как будет брошен OOME
• Применение
• memory-sensitive caches
• Можно контроллировать агрессивность очистки
• -XX:SoftRefLRUPolicyMSPerMB
18
19. Типы ссылок
WeakReference
• Наличие «слабой» ссылки не мешает GC удалить
объект
• Действия GC
• Атомарно очищает все «слабые» ссылки на объект
• Если надо, помещает объекты на финализацию
• Если надо, помещает «слабые» ссылки в очередь
• Использование
• canonicalizing mappings (interned strings)
19
20. Типы ссылок
PhantomReference
• Замена финализаторам
– protected void Object::finalize()
• Невозможно получить ссылку на объект
– PhantomReference.get() == null
• GC помещает «фантомные» ссылки в очередь
20
21. Типы ссылок
Чем плохи финализаторы?
• Замедление аллокации
– Требуется регистрация объектов с нетривиальными
финализаторами
• 2 цикла GC для удаления объекта
• Возможность «воскрешения» объекта
• Недетерминированный порядок исполнения
• Могут начать выполняться раньше чем кажется
• Многопоточность (даже в однопоточном приложении)
– Требуется синхронизация при доступе к структурам данных
21
22. Типы ссылок в Java
Оповещения об изменении достижимости объекта
• Помещение ссылки в очередь
• java.lang.ref.ReferenceQueue
• Получить оповещение, когда объект становится
• softy reachable
• weakly reachable
• phantom reachable
• Невозможно «воскресить» объект из очереди
– Reference.get() == null
22
23. Типы ссылок в Java
Автоматическая очиста ссылок
• «Мягкие» и «слабые» ссылки
• Автоматически очищаются GC перед добавлением в очередь
• Регистрация в очереди не обязательна
• «Фантомные» ссылки
• Обязаны быть зарегистрированы в очереди
• Объект остается phantom-достижим пока все достижимые
«фантомные» ссылки не очищены
23
24. Типы ссылок в Java
Резюме
• «Мягкие» ссылки
– очищаются при нехватке памяти в системе
– GC-friendly кэширование объектов
• «Cлабые» ссылки
– очищаются если на объект есть только «слабые» ссылки
– canonicalizing mappings (e.g. interned strings)
• «Фантомные» ссылки
– сообщение о «смерти» объекта
– освобождение ресурсов, ассоциированных с объектом
– надежнее финализаторов
24
25. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
25
26. Разное…
Советы
• ThreadLocal + ThreadPool = ?
– «засоряют» пулы потоков
• Коллекции
– много пустых коллекций в приложении
– начальный размер может быть слишком велик
– выставлять желаемый размер явно при создании
• Массивы
– создавать перед использованием
– DirectByteBuffer vs byte[]
• используйте NIO для I/O вместо массивов
• не копирует данные
– пул <*>[]? фрагментация
26
27. Анализ содержимого «кучи» приложения
• Суммарный размер объектов по классам
$ jmap –histo[:live] <pid>
• Копия содержимого «кучи» (heap dump)
– Как получить
$ jmap –dump:live,format=b,file=<file> <pid>
$ java –XX:+HeapDumpOnOutOfMemoryError …
– Как анализировать heap dump?
• JHAT – Java Heap Analysis Tool
• $ jhat <file>
• http://localhost:7000
• поддерживает OQL (Object Query Language)
27
28. Содержание
• Введение
• Структура «кучи» в Java
• «Сжатые» указатели
• Представление объекта в памяти
• Типы ссылок
• Разное
• Итоги
28
29. Итоги
• Для комфортной работы GC требуется достаточно
свободного места в «куче»
• «Сжатые» указатели работают только до 32Gb
• Неоптимальное представление данных может
серьезно увеличить расход памяти
• За счет java.lang.ref.* API можно уменьшить расход
памяти приложением
29