Документация Engee

Управление памятью и сборка мусора

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

Обзор сборки мусора

В Julia реализован сборщик мусора со следующими особенностями:

  • Неперемещающий: во время сборки мусора объекты не перемещаются в памяти.

  • Учитывающий поколения объектов: более новые объекты собираются чаще, чем более старые.

  • Параллельный и частично одновременный: сборщик мусора может использовать несколько потоков и работать параллельно с вашей программой.

  • Почти точный: сборщик мусора точно идентифицирует ссылки на объекты в чистом коде Julia и предоставляет консервативные API сканирования для пользователей, вызывающих Julia из C.

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

Архитектура памяти

В Julia используется двухуровневая стратегия выделения памяти:

  • Небольшие объекты (в настоящее время ≤ 2032 байта, но порог может измениться): память выделяется с использованием быстрого средства выделения пула для каждого потока.

  • Большие объекты: память выделяется напрямую с использованием malloc системы.

Такой гибридный подход оптимизирует как скорость выделения памяти, так и ее эффективность. При этом средство выделения пула обеспечивает быстрое выделение памяти для множества небольших объектов, типичных для программ на Julia.

Требования к памяти системы

Размер файла подкачки

Сборщик мусора Julia разработан с учетом того, что в вашей системе настроен достаточный размер файла подкачки. Сборщик мусора использует эвристические методы, предполагающие возможность выделения памяти сверх размера физической оперативной памяти при необходимости, полагаясь на систему управления виртуальной памятью операционной системы.

Если в системе нет файла подкачки или его размер ограничен, во время сборки мусора могут возникать ошибки нехватки памяти. В таких случаях можно использовать параметр --heap-size-hint для ограничения использования памяти средой Julia.

Указания в отношении памяти

Julia можно дать указание в отношение максимального объема используемой памяти:

julia --heap-size-hint=4G  # Задаем указание ~4 ГБ
julia --heap-size-hint=50% # или 50 % физической памяти

Параметр --heap-size-hint предписывает сборщику мусора запускать сборку более активно при приближении к указанному пределу. Это особенно полезно в следующих случаях:

  • контейнеры с ограничениями памяти;

  • системы без файла подкачки;

  • системы с общим доступом, где необходимо ограничить потребление памяти средой Julia.

Это также можно настроить с помощью переменной среды JULIA_HEAP_SIZE_HINT:

export JULIA_HEAP_SIZE_HINT=2G
julia

Многопоточная сборка мусора

Сборщик мусора Julia может использовать несколько потоков для повышения производительности в многоядерных системах.

Конфигурация потоков для сборщика мусора

По умолчанию Julia использует несколько потоков для сборки мусора:

  • Потоки маркировки: используются на этапе маркировки для отслеживания ссылок на объекты (по умолчанию 1 поток, который также является и вычислительным, если поток только один; в противном случае половина от общего числа вычислительных потоков).

  • Потоки очистки: используются для одновременной очистки освобожденной памяти (по умолчанию 0, отключено).

Потоки сборщика мусора можно настроить так:

julia --gcthreads=4,1  # 4 потока маркировки, 1 поток очистки
julia --gcthreads=8    # 8 потоков маркировки, 0 потоков очистки

Или с помощью переменной среды:

export JULIA_NUM_GC_THREADS=4,1
julia

Рекомендации

Для рабочих нагрузок с интенсивными вычислениями:

  • Используйте несколько потоков маркировки (обычно подходит конфигурация по умолчанию).

  • Для рабочих нагрузок с интенсивным выделением памяти рекомендуется включить параллельную очистку с использованием одного потока очистки.

Для рабочих нагрузок с интенсивным использованием памяти:

  • Включите параллельную очистку, чтобы сократить паузы в сборке мусора.

  • Отслеживайте время сборки мусора с помощью @time и соответствующим образом корректируйте количество потоков.

Мониторинг и отладка

Базовый мониторинг памяти

Для отслеживания выделения памяти и накладных расходов сборщика мусора используйте макрос @time:

julia> @time some_computation()
  2.123456 seconds (1.50 M allocations: 58.725 MiB, 17.17% gc time)

Ведение журнала статистики сборки мусора

Включите ведение подробного журнала сборщика мусора для анализа закономерностей:

julia> GC.enable_logging(true)
julia> # Выполняем код
julia> GC.enable_logging(false)

В журнале регистрируется каждое событие сборки мусора, включая статистику по времени и использованию памяти.

Ручное управление сборкой мусора

Хотя делать это обычно не рекомендуется, вы можете запустить сборку мусора вручную:

GC.gc()          # Принудительно запускаем сборку мусора
GC.enable(false) # Отключаем автоматическую сборку мусора (использовать с осторожностью!)
GC.enable(true)  # Снова включаем автоматическую сборку мусора

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

Замечания по производительности

Сокращение выделяемой памяти

Лучший способ минимизировать влияние сборщика мусора — избегать лишнего выделения памяти:

  • По возможности используйте операции на месте (например, x .+= y вместо x = x + y).

  • Предварительно выделяйте память для массивов и используйте их повторно.

  • Избегайте создания временных объектов в сплошных циклах.

  • По возможности используйте StaticArrays.jl для небольших массивов фиксированного размера.

Эффективные с точки зрения памяти шаблоны

  • Избегайте изменения типа глобальных переменных.

  • Используйте const для глобальных констант.

Профилирование использования памяти

Подробные указания по профилированию выделения памяти и выявлению узких мест производительности см. в разделе Профилирование.

Расширенная настройка

Интеграция с управлением памятью системы

Julia работает оптимально при следующих условиях:

  • В системе достаточный размер файла подкачки (рекомендуется в 2 раза больше объема физической оперативной памяти).

  • Виртуальная память правильно настроена.

  • Другие процессы оставляют достаточный объем доступной памяти.

  • Ограничения на использование памяти контейнерами заданы соответствующим образом с помощью --heap-size-hint.

Устранение неполадок с памятью

Большие накладные расходы на сборку мусора

Если сборка мусора занимает слишком много времени:

  1. Уменьшите скорость выделения: постарайтесь улучшить алгоритмы.

  2. Настройте потоки сборщика мусора: поэкспериментируйте с различными настройками --gcthreads.

  3. Используйте параллельную очистку: включите фоновую очистку с помощью параметра --gcthreads=N,1.

  4. Профилируйте шаблоны использования памяти: выявите проблемные места в выделении памяти и оптимизируйте их.

Утечки памяти

Хотя сборщик мусора в Julia предотвращает большинство утечек памяти, проблемы все же могут возникать:

  • Глобальные ссылки: избегайте хранения ссылок на большие объекты в глобальных переменных.

  • Замыкания: с осторожностью используйте замыкания, которые записывают большие объемы данных.

  • Взаимодействие с C: обеспечьте надлежащую очистку при взаимодействии с библиотеками C.

Более подробные сведения о внутренних принципах работы сборщика мусора Julia см. в разделе «Сборка мусора» в документации для разработчиков.