3. 3
Введение
О чем пойдет речь?
• Производительность GC
• 3 характеристики
• Throughput
• Объем вычислительных ресурсов, затрачиваемых на GC
• Предсказуемость
• На какое время прерывается работа приложения
• Footprint
• Объем используемой памяти
6. 6
Критерии выбора размера «кучи»
• Чем больше памяти, тем лучше для GC
• Как для молодого, так и для старшего поколения
• Более редкие сборки
• Ниже затраты на сборку мусора
• Доступный объем памяти ограничен
• Физическая память
• 32-битный режим
• Наличие других приложений в системе
8. 8
«Сжатые» указатели
-XX:+UseCompressedOops
• 32-битные указатели в 64-битном режиме
• oop - Ordinary Object Pointer
Размер
«кучи»
<
4Gb
>=
4Gb
<
26Gb
>=
26Gb
<
32Gb
Режим
работы
Zero-‐based
non-‐aligned
Zero-‐based
8-‐byte
aligned
Offset-‐based
8-‐byte
aligned
Декоди-‐
рование
не
требуется
x
<<
3
offset
+
x
<<
3
9. 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
11. 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
12. 12
Представление объекта в памяти
• new int[1000]
• 32-бита: 4+4+4+1000*4 =
4012 байт
• 64-бита: 8+8+4+1000*4 =
4020 байт
• new Integer[1000]
• 32-бита: 4+4+4+1000*(4+4+4+4) =
16012 байт
• 64-бита: 8+8+4+1000*(8+8+8+4) =
28020 байт
14. 14
Инженерная проблема
Кэширование данных
• Приложение оперирует объемами данных,
существенно превышающими доступную память
• Требуется организовать кэширование на уровне
приложения
15. 15
Типы ссылок в Java
• Декларативный API к GC
• Контроль достижимости
• Представлены в виде объектов
• extends java.lang.ref.Reference
• 3 типа
• «мягкие»
• java.lang.ref.SoftReference
• «слабые»
• java.lang.ref.WeakReference
• «фантомные»
• java.lang.ref.PhantomReference
16. 16
Типы ссылок в Java
Как использовать?
import java.lang.ref.*;
Object obj = new Object(); // strong reference
17. 17
Типы ссылок в 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
18. 18
Типы ссылок в 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) { … }
20. 20
Типы ссылок
SoftReference
• Удаление softly reachable объекта при нехватке
памяти в системе
• Гарантии
• Все «мягкие» ссылки к soft-достижимым объектам будут
очищены до того, как будет брошен OOME
• Применение
• memory-sensitive caches
• Можно контроллировать агрессивность очистки
• -XX:SoftRefLRUPolicyMSPerMB
21. 21
Типы ссылок
WeakReference
• Наличие «слабой» ссылки не мешает GC удалить
объект
• Действия GC
• Атомарно очищает все «слабые» ссылки на объект
• Если надо, помещает объекты на финализацию
• Если надо, помещает «слабые» ссылки в очередь
• Использование
• canonicalizing mappings (interned strings)
22. 22
Типы ссылок
PhantomReference
• Замена финализаторам
– protected void Object::finalize()
• Невозможно получить ссылку на объект
– PhantomReference.get() == null
• GC помещает «фантомные» ссылки в очередь
23. 23
Типы ссылок
Чем плохи финализаторы?
• Замедление аллокации
– Требуется регистрация объектов с нетривиальными
финализаторами
• 2 цикла GC для удаления объекта
• Возможность «воскрешения» объекта
• Недетерминированный порядок исполнения
• Могут начать выполняться раньше чем кажется
• Многопоточность (даже в однопоточном приложении)
– Требуется синхронизация при доступе к структурам данных
24. 24
Типы ссылок в Java
Оповещения об изменении достижимости объекта
• Помещение ссылки в очередь
• java.lang.ref.ReferenceQueue
• Получить оповещение, когда объект становится
• softy reachable
• weakly reachable
• phantom reachable
• Невозможно «воскресить» объект из очереди
– Reference.get() == null
25. 25
Типы ссылок в Java
ReferenceQueue: Как использовать?
import java.lang.ref.*;
Object obj = new Object(); // strong reference
// phantom reference
ReferenceQueue reqQueue = new ReferenceQueue(obj);
Reference phantomRef = new PhantomReference(obj, refQueue);
26. 26
Типы ссылок в Java
Автоматическая очиста ссылок
• «Мягкие» и «слабые» ссылки
• Автоматически очищаются GC перед добавлением в очередь
• Регистрация в очереди не обязательна
• «Фантомные» ссылки
• Обязаны быть зарегистрированы в очереди
• Объект остается phantom-достижим пока все достижимые
«фантомные» ссылки не очищены
27. 27
Типы ссылок в Java
Резюме
• «Мягкие» ссылки
– очищаются при нехватке памяти в системе
– GC-friendly кэширование объектов
• «Cлабые» ссылки
– очищаются если на объект есть только «слабые» ссылки
– canonicalizing mappings (e.g. interned strings)
• «Фантомные» ссылки
– сообщение о «смерти» объекта
– освобождение ресурсов, ассоциированных с объектом
– надежнее финализаторов
29. 29
Разное…
Советы
• ThreadLocal + ThreadPool = ?
– «засоряют» пулы потоков
• Коллекции
– много пустых коллекций в приложении
– начальный размер может быть слишком велик
– выставлять желаемый размер явно при создании
• Массивы
– создавать перед использованием
– DirectByteBuffer vs byte[]
• используйте NIO для I/O вместо массивов
• не копирует данные
– пул <*>[]? фрагментация
30. 30
Анализ содержимого «кучи»
приложения
• Суммарный размер объектов по классам
$ 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)
32. 32
Итоги
• Для комфортной работы GC требуется достаточно
свободного места в «куче»
• «Сжатые» указатели работают только до 32Gb
• Неоптимальное представление данных может
серьезно увеличить расход памяти
• За счет java.lang.ref.* API можно уменьшить расход
памяти приложением