Что такое корни (roots) в сборщике мусора и где они находятся
Что проверяют
Знаете ли вы, откуда сборщик начинает обход, и связываете ли это с утечками в приложении. В Android вопрос почти всегда прикладной: собеседующий хочет услышать, почему закрытый экран не освобождается и как такое находят.
Как отвечать
Корни это ссылки, которые среда исполнения считает живыми без проверки: локальные переменные и параметры в кадрах стека всех живых потоков, сами живые потоки, статические поля загруженных классов, глобальные ссылки JNI из нативного кода и из привязок к системным службам.
Всё, до чего можно дойти по ссылкам от корней, живёт, остальное собирается. Важно, что живой поток сам является корнем: фоновый поток или корутина в собственной области удерживает всё, что захватила, даже после закрытия экрана.
Прикладная часть ответа весит больше определения. Классические удержания: статическое поле со ссылкой на контекст экрана, нестатический внутренний класс или обработчик сообщений, держащий внешний объект, слушатель, зарегистрированный в долгоживущем компоненте и не снятый, отложенное сообщение в очереди. Ищут это по снимку кучи: профилировщик показывает цепочку ссылок от корня до объекта, тем же занята известная библиотека поиска утечек.
Лечение почти всегда одно: привязать время жизни к жизненному циклу владельца и брать контекст приложения там, где экран не нужен.
Где спотыкаются
Думают, что корень это про важность объекта, и говорят, будто данные, на которые ссылается статическое поле, соберутся. Всё наоборот: они удержаны именно потому, что достижимы.
Путают утечку с нехваткой памяти. Утечка это достижимый объект, который больше не нужен, сборщик работает правильно и обязан его сохранить, чинить надо лишнюю ссылку.
Надеются на обнуление полей и ручной запрос сборки. Сбросить поле имеет смысл, только если это была последняя ссылка, а просьба собрать мусор удержание не снимает и на времени жизни объекта не сказывается.