В чем разница между стековой и кучей памятью
Что проверяют
Понимаете ли вы разницу во времени жизни и знаете ли специфику ограничений в Android.
Как отвечать
Стек свой у каждого потока. Хранит кадры вызовов: локальные переменные примитивных типов, ссылки на объекты, адрес возврата. Работает по принципу «последним пришёл, первым ушёл», выделение это сдвиг указателя, освобождение происходит автоматически при выходе из метода. Размер ограничен, и глубокая рекурсия даёт StackOverflowError.
Куча общая для всех потоков. Здесь живут все объекты и массивы, освобождает их сборщик мусора среды выполнения. Выделение дороже, доступ медленнее из-за разброса по памяти. Переполнение даёт OutOfMemoryError.
Правило: объект всегда в куче, в стеке только ссылка на него. Локальная переменная типа String это ссылка в кадре, указывающая на объект в куче.
Специфика Android, которую и хотят услышать:
- лимит на процесс, а не на устройство. Приложению выделяется ограниченный объём кучи, зависящий от устройства, часто от 128 до 512 МБ. Свободная память телефона тут ни при чём, и
OutOfMemoryErrorвозможен при гигабайтах свободных. ФлагlargeHeapв манифесте поднимает предел, но это не решение проблемы, а отсрочка; - растровые изображения это главный потребитель кучи. Несжатое изображение занимает ширину на высоту на четыре байта, и полноразмерная фотография легко съедает десятки мегабайт. Отсюда обязательное масштабирование при загрузке;
- утечки удерживают объекты, которые должны были умереть. Классика это ссылка на активити в долгоживущем объекте, из-за чего экран не собирается. Ловится LeakCanary;
- профилировщик памяти в Android Studio показывает распределение и позволяет снять дамп кучи.
Где спотыкаются
Считают, что примитивное поле объекта лежит в стеке.
Думают, что предел памяти зависит от объёма памяти устройства.
Включают largeHeap вместо поиска утечки.
Загружают изображения в полном разрешении в список.