Управление памятью в Nim
"Дорога в ад вымощена благими намерениями."
Введение
Этот документ описывает работу многопарадигменных стратегий управления памятью. Как настроить сборщики мусора для ваших нужд, таких как (мягкое) реальное время, и как работают стратегии управления памятью, которые не являются сборщиками мусора.
Стратегии управления памятью для разных парадигм
Для выбора стратегии управления памятью используйте переключатель --gc:.
-
--gc:refc. Это по умолчанию GC. Это отложенный сборщик мусора на основе подсчета ссылок с простым резервным сборщиком мусора Mark&Sweep для сбора циклов. Кучи являются локальными для потока. -
--gc:markAndSweep. Простой сборщик мусора на основе Mark-And-Sweep. Кучи являются локальными для потока. -
--gc:boehm. Сборщик мусора на основе Boehm, он предлагает общую кучу. -
--gc:go. Сборщик мусора Go, полезный для взаимодействия с Go. Предлагает общую кучу. -
--gc:arc. Простой подсчет ссылок с оптимизациями семантики перемещения, предлагает общую кучу. Он обеспечивает детерминированную производительность для жесткореальных систем. Циклы ссылок приводят к утечкам памяти, будьте осторожны. -
--gc:orc. То же, что и--gc:arc, но добавляет сборщик циклов на основе "испытательного удаления". К сожалению, это усложняет анализ профиля производительности, поэтому он менее полезен для систем жесткого реального времени. -
--gc:none. Никакой стратегии управления памятью и сборщика мусора. Выделенная память просто никогда не освобождается. Вы должны использовать--gc:arcвместо этого.
| Управление памятью | Куча | Циклы ссылок | Остановка мира | Переключатель командной строки |
|---|---|---|---|---|
| RefC | Локальная | Сборщик циклов | Нет | --gc:refc |
| Mark & Sweep | Локальная | Сборщик циклов | Нет | --gc:markAndSweep |
| ARC | Общая | Утечка | Нет | --gc:arc |
| ORC | Общая | Сборщик циклов | Нет | --gc:orc |
| Boehm | Общая | Сборщик циклов | Да | --gc:boehm |
| Go | Общая | Сборщик циклов | Да | --gc:go |
| Нет | Ручная | Ручная | Ручная | --gc:none |
Сборщик мусора JavaScript используется для JavaScript и NodeJS целевых компиляций. Целевая компиляция NimScript использует стратегию управления памятью, встроенную в компилятор Nim.
Настройка сборщика мусора refc
Сборщик циклов
Сборщик циклов можно включить/выключить независимо от других частей сборщика мусора с помощью GC_enableMarkAndSweep и GC_disableMarkAndSweep.
Поддержка мягкого реального времени
Для включения поддержки реального времени необходимо определить символ useRealtimeGC с помощью --define:useRealtimeGC (вы можете поместить его также в свой конфигурационный файл). С этим переключателем сборщик мусора поддерживает следующие операции:
proc GC_setMaxPause*(maxPauseInUs: int) proc GC_step*(us: int, strongAdvice = false, stackSize = -1)
Единицей параметров maxPauseInUs и us является микросекунда.
Эти две процедуры — это два способа работы сборщика мусора реального времени:
(1) Режим GC_SetMaxPause
Вы можете вызвать
GC_SetMaxPauseпри запуске программы, и затем каждый запущенный цикл сборки мусора пытается не занимать болееmaxPauseвремени. Однако возможно (и часто бывает), что работа не распределяется равномерно, так как каждый вызовnewможет запустить цикл сборки мусора и, следовательно, занятьmaxPauseвремени.
(2) Режим GC_step
Это позволяет сборщику мусора выполнить некоторую работу в течение
usвремени. Это полезно для вызова в основном цикле, чтобы убедиться, что сборщик мусора может выполнить свою работу. Чтобы привязать всю деятельность сборщика мусора к вызовуGC_step, отключите сборщик мусора с помощьюGC_disableпри запуске программы. ЕслиstrongAdviceустановлено вtrue, сборщик мусора будет вынужден выполнить цикл сбора. В противном случае сборщик мусора может решить ничего не делать, если нет много мусора для сбора. Вы также можете указать текущий размер стека через параметрstackSize. Это может повысить производительность, если вы знаете, что нет уникальных ссылок Nim ниже определенной точки в стеке. Убедитесь, что указанный размер больше потенциального наихудшего случая.Это может повысить производительность, если вы знаете, что нет уникальных ссылок Nim ниже определенной точки в стеке. Убедитесь, что указанный размер больше потенциального наихудшего случая.
Эти процедуры предоставляют «лучшую возможную» гарантию реального времени; в частности, сборщик циклов не учитывает сроки. Отключите его, чтобы получить более предсказуемое поведение в режиме реального времени. Тесты показывают, что время максимальной паузы 1 мс будет соблюдаться практически во всех случаях на современных процессорах (с отключенным сборщиком циклов).
Измерение времени с помощью сборщиков мусора
Сборщики мусора измеряют время следующим образом (см. lib/system/timers.nim для реализации):
-
QueryPerformanceCounterиQueryPerformanceFrequencyв Windows. -
mach_absolute_timeв Mac OS X. -
gettimeofdayв системах Posix.
Таким образом, он поддерживает разрешение в наносекунды внутри; однако API для удобства использует микросекунды.
Определите символ reportMissedDeadlines чтобы сборщик мусора выводил сообщения, когда он пропустил срок. Сообщения будут улучшены и поддержаны API в будущих версиях сборщика.
Настройка сборщика мусора
Сборщик проверяет, осталось ли время для работы после каждой workPackage-й итерации. В настоящее время это установлено в 100, что означает, что до 100 объектов проходят обход и освобождаются, прежде чем он снова проверяет. Таким образом, workPackage влияет на точность измерения времени и может потребовать настройки в специализированных средах или на старом оборудовании.
Отслеживание памяти
Если вам нужно передавать память, выделенную Nim, в C, вы можете использовать процедуры GC_ref и GC_unref для маркировки объектов как ссылочных, чтобы избежать их освобождения сборщиком мусора. Другие полезные процедуры из system, которые вы можете использовать для отслеживания памяти:
-
getTotalMem()Возвращает количество всей управляемой сборщиком мусора памяти. -
getOccupiedMem()Байты, зарезервированные сборщиком мусора и используемые объектами. -
getFreeMem()Байты, зарезервированные сборщиком мусора и не используемые. -
GC_getStatistics()Статистика сборщика мусора в виде удобочитаемой строки.
Эти числа обычно относятся только к работающему потоку, а не ко всей куче, за исключением --gc:boehm и --gc:go.
Помимо GC_ref и GC_unref вы можете избежать сборщика мусора, вручную выделяя память с помощью процедур, таких как alloc, alloc0, allocShared, allocShared0 или allocCStringArray. Сборщик мусора не будет пытаться освободить их; вам нужно вызвать соответствующие пары dealloc (dealloc, deallocShared, deallocCStringArray, и т. д.) после завершения работы с ними, иначе они будут утекать.
Сброс кучи
Функция сброса кучи все еще находится на начальном этапе развития, но уже оказалась полезной для нас, поэтому она может быть полезна и для вас. Для получения сброса кучи компилируйте с -d:nimTypeNames и вызывайте dumpNumberOfInstances в стратегической точке вашей программы. Это создаст список используемых типов в вашей программе и для каждого типа общее количество экземпляров объектов этого типа, а также общее количество байтов, занимаемых этими экземплярами. Этот список в настоящее время не отсортирован! Вам потребуется использовать внешнюю обработку сценариев оболочки для сортировки.
Числа подсчитывают количество объектов во всех кучах сборщика мусора, они относятся ко всем запущенным потокам, а не только к текущему потоку. (Текущий поток — это поток, который вызывает dumpNumberOfInstances.) В будущих версиях это может измениться.
© 2006–2021 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/gc.html