Управление памятью в Kotlin/Native
Kotlin/Native использует современный менеджер памяти, аналогичный JVM, Go и другим распространённым технологиям:
Объекты хранятся в общей куче и могут быть доступны из любого потока.
Регулярно выполняется сборка мусора (GC), чтобы очистить объекты, недоступные из «корней», таких как локальные и глобальные переменные.
Менеджер памяти одинаков для всех целей Kotlin/Native, за исключением wasm32, который поддерживается только в устаревшем менеджере памяти.
Сборщик мусора
Точный алгоритм работы GC постоянно развивается. По состоянию на 1.7.20, используется сборщик мусора Stop-the-World Mark and Concurrent Sweep, который не разделяет кучу на поколения.
GC выполняется в отдельном потоке и запускается на основе таймера и эвристики давления памяти, или может быть вызван вручную.
Включение сборки мусора вручную
Чтобы принудительно запустить сборщик мусора, вызовите kotlin.native.internal.GC.collect(). Это запускает новую коллекцию и ожидает её завершения.
Отслеживание производительности GC
Пока нет специальных инструментов для отслеживания производительности GC. Однако всё ещё можно просмотреть журналы GC для диагностики. Чтобы включить протоколирование, задайте соответствующий флаг компиляции в скрипте Gradle:
-Xruntime-logs=gc=info
В настоящее время журналы выводятся только в stderr.
Отключение сборки мусора
Рекомендуется держать GC включённым. Однако, в некоторых случаях, например, для тестирования или если у вас кратковременная программа, вы можете его отключить. Для этого задайте соответствующий флаг компиляции в скрипте Gradle:
-Xgc=noop
Потребление памяти
С менеджером памяти Kotlin/Native можно отслеживать потребление памяти. Вы можете проверять утечки памяти и при необходимости корректировать потребление.
Поиск утечек памяти
Для доступа к метрикам менеджера памяти вызовите kotlin.native.internal.GC.lastGCInfo(). Он возвращает статистику последнего запуска сборщика мусора. Статистика может быть полезна для:
Отладки утечек памяти при использовании глобальных переменных
Проверки наличия утечек при запуске тестов
import kotlin.native.internal.*
import kotlin.test.*
class Resource
val global = mutableListOf<Resource>()
@OptIn(ExperimentalStdlibApi::class)
fun getUsage() : Long {
GC.collect()
return GC.lastGCInfo!!.memoryUsageAfter["heap"]!!.totalObjectsSizeBytes
}
fun run() {
global.add(Resource())
// The test will fail if you remove the next line
global.clear()
}
@Test
fun test() {
val before = getUsage()
// A separate function is used to ensure that all temporary objects are cleared
run()
val after = getUsage()
assertEquals(before, after)
}
Настройка потребления памяти
Если в программе нет утечек памяти, но вы всё ещё видите неожиданно высокое потребление памяти, попробуйте обновить Kotlin до последней версии. Мы постоянно улучшаем менеджер памяти, поэтому даже простое обновление компилятора может улучшить потребление памяти.
Другой способ исправить высокое потребление памяти связан с mimalloc, стандартным менеджером памяти для многих целей. Он предварительно выделяет и удерживает системную память, чтобы ускорить выделение.
Чтобы избежать этого с потерей производительности, доступны несколько вариантов:
Переключите менеджер памяти с
mimallocна системный менеджер. Для этого задайте опцию-Xallocator=stdв скрипте Gradle.-
Начиная с Kotlin 1.8.0-Beta, вы также можете указать
mimallocнемедленно освободить память обратно в систему. Это немного снижает производительность, но даёт менее определённые результаты.Для этого включите следующую опцию в вашем файле
gradle.properties:kotlin.native.binary.mimallocUseCompaction=true
-
Переключитесь на пользовательский менеджер памяти. Он всё ещё Бета. Чтобы попробовать его в своих проектах, установите опцию
-Xallocator=customв вашем скрипте Gradle.Для получения дополнительной информации об архитектуре нового менеджера памяти, см. этот README.
Если ни один из этих вариантов не помог улучшить потребление памяти, сообщите об ошибке в YouTrack.
Единые тесты в фоновом режиме
В единых тестах ничего не обрабатывает очередь основного потока, поэтому не используйте Dispatchers.Main , если это не было смоделировано, что можно сделать, вызвав Dispatchers.setMain из kotlinx-coroutines-test.
Если вы не полагаетесь на kotlinx.coroutines или Dispatchers.setMain по какой-либо причине не работает, попробуйте следующее решение для реализации загрузчика тестов:
Затем скомпилируйте бинарный файл теста с флагом компиляции -e testlauncher.mainBackground.
Устаревший менеджер памяти
Если необходимо, вы можете вернуться к устаревшему менеджеру памяти. Установите указанную опцию в вашем gradle.properties:
kotlin.native.binary.memoryModel=strict
Если у вас возникли проблемы с миграцией с устаревшего менеджера памяти или вы хотите временно поддерживать как текущий, так и устаревший менеджеры памяти, см. наши рекомендации в руководстве по миграции.
Что дальше
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/native-memory-manager.html