Какой максимальный объем оперативной памяти может использовать приложение?

145

Мне весьма любопытен вопрос об управлении памятью операционной системы Android, поэтому я надеюсь получить достаточно подробный ответ по этой теме.

Что я хотел бы знать:

  • Какой максимальный объем памятимегабайтах / в процентах от общего объема ОЗУ) может использовать приложение Android (которое не является системным приложением)?
  • Есть ли различия между версиями Android ?
  • Есть ли какие-либо различия в отношении производителя устройства?

И, самое главное:

  • Что считается / от чего зависит, когда речь заходит о системе, определяющей, сколько ОЗУ приложение может использовать во время выполнения (при условии, что максимум памяти для приложения не является статическим числом)?

Что я слышал до сих пор (до 2013 года):

  • Ранние устройства Android имели ограничение на 16 МБ на приложение
  • Позже эта крышка увеличилась до 24 МБ или 32 МБ

Что делает меня очень любопытным:

Оба эти предела очень низкие.

Я недавно загрузил диспетчер задач Android, чтобы проверить оперативную память моих устройств. Что я заметил, так это то, что есть приложения, использующие около 40-50 мегабайт оперативной памяти, что, безусловно, превышает упомянутое максимальное использование оперативной памяти, скажем, 32 МБ. Так как же Android определяет, сколько ОЗУ может использовать приложение? Как это возможно, что приложения превышают этот лимит?

Кроме того, я заметил, что некоторые мои приложения аварийно завершают работу (убивают системой?) С исключением OutOfMemoryException при использовании около 30-40 мегабайт. С другой стороны, у меня на телефоне работают приложения, использующие 100 МБ и более через некоторое время (возможно, из-за утечек памяти), которые не вылетают и не убиваются. Так что, очевидно, это также зависит от самого приложения, когда дело доходит до определения того, сколько ОЗУ можно сэкономить. Как это возможно? (Я провел свои тесты с HTC One S с 768 МБ ОЗУ)

Отказ от ответственности: Я НЕ связан ни с каким приложением Android Task Manager.

Филипп Яхода
источник

Ответы:

119

Какой максимальный объем памяти (в мегабайтах / в процентах от общего объема ОЗУ) может использовать приложение Android (которое не является системным приложением)?

Это зависит от устройства. getMemoryClass()onActivityManager даст вам значение для устройства, на котором работает ваш код.

Есть ли различия между версиями Android?

Да, поскольку требования к ОС с годами возросли, и устройства должны быть настроены в соответствии.

Существуют ли различия в отношении производителя устройства?

Да, поскольку производители производят устройства, а размер зависит от устройства.

Какие «побочные факторы» учитываются при определении объема оперативной памяти, которую может использовать приложение?

Я понятия не имею, что означает «побочные факторы».

Ранние устройства имели ограничение по каждому приложению 16 МБ; Более поздние устройства увеличили это до 24 МБ или 32 МБ

Это примерно так. Разрешение экрана является существенным фактором, поскольку большие разрешения означают большие битовые карты, и поэтому планшеты и телефоны с высоким разрешением будут иметь более высокие значения. Например, вы увидите устройства с кучей 48 МБ, и я не удивлюсь, если будут значения выше этого.

Как это возможно, что приложения превышают этот лимит?

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

При этом собственный код (NDK) не подлежит ограничению кучи. И, начиная с Android 3.0, приложения могут запрашивать «большую кучу», обычно в диапазоне сотен МБ, но это считается плохой формой для большинства приложений.

Кроме того, я заметил, что некоторые мои приложения аварийно завершают работу с OutOfMemoryException при использовании около 30-40 мегабайт.

Имейте в виду, что сборщик мусора Android не является компактным сборщиком мусора. Исключение действительно должно быть CouldNotFindSufficientlyLargeBlockOfMemoryException, но это, вероятно, считалось слишком многословным. OutOfMemoryExceptionозначает, что вы не можете выделить запрашиваемый блок , но не полностью исчерпали свою кучу.

CommonsWare
источник
Я не могу понять таблицу, у меня Xperia X mobile с разрешением 1080 x 1920, которое является большим разрешением, и другое устройство Samsung Tab 4 с разрешением 800 x 1280, так что его занимает та же самая оперативная память, пожалуйста, помогите мне, потому что мобильный поставляется с 3 ГБ ОЗУ и вкладка поставляется с 1,5 ГБ ОЗУ, поэтому планшет занимает большой оперативной памяти из-за большого экрана?
Рахул Мандалия
@RahulMandaliya: Извините, но я не понимаю вашу озабоченность или как это связано с этим вопросом. Возможно, вы захотите открыть отдельный вопрос о переполнении стека, в котором подробно объясните, что вас беспокоит.
CommonsWare
15

Это конец 2018 года, так что все изменилось.

Прежде всего: запустите приложение и откройте вкладку Android Profiler в Android Studio. Вы увидите, сколько памяти он потребляет, вы будете удивлены, но он может выделить много оперативной памяти.

Также здесь есть отличная статья в официальных документах с подробными инструкциями о том, как использовать Memory Profiler, которая может дать вам всесторонний обзор управления вашей памятью.

Но в большинстве случаев вам будет достаточно обычного Android Profiler.

введите описание изображения здесь

Обычно приложение запускается с 50 МБ памяти, но при загрузке некоторых фотографий в память мгновенно увеличивается до 90 МБ. Когда вы открываете Activity с помощью ViewPager с предварительно загруженными фотографиями (по 3,5 МБ каждая), вы можете легко получить 190 МБ за несколько секунд.

Но это не значит, что у вас есть проблемы с управлением памятью.

Лучший совет, который я могу дать, - следовать рекомендациям и рекомендациям, использовать лучшие библиотеки для загрузки изображений (Glide, Picasso), и все будет в порядке.


Но если вам нужно что-то адаптировать, и вам действительно нужно знать, сколько памяти вы можете выделить вручную, вы можете получить полную свободную память и рассчитать заранее определенную часть (в%) из нее. В моем случае мне нужно было кэшировать расшифрованные фотографии в памяти, поэтому мне не нужно расшифровывать их каждый раз, когда пользователь просматривает список.

Для этого вы можете использовать готовый к использованию класс LruCache . Это класс кеша, который автоматически отслеживает, сколько памяти выделяют ваши объекты (или количество экземпляров), и удаляет самые старые, чтобы сохранить последние по истории их использования. Вот отличный урок о том, как его использовать.

В моем случае я создал 2 экземпляра кешей: для больших пальцев и вложений. Сделайте их статичными с одноэлементным доступом, чтобы они были доступны во всем приложении.

класс кеша:

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}


@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

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

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

И вот как я использую его в адаптерах для получения кэшированного изображения:

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

и как я устанавливаю его в кэш в фоновом потоке (обычный AsyncTask):

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

Мое приложение предназначено для API 19+, поэтому устройства не устарели, и в моем случае эти части доступной оперативной памяти достаточно хороши для кэширования (1% и 3%).

Интересный факт: Android не имеет API или других хаков, чтобы получить объем памяти, выделенный для вашего приложения, он рассчитывается на лету на основе различных факторов.


PS Я использую поле статического класса для хранения кэша, но в соответствии с последними рекомендациями Android рекомендуется использовать для этой цели компонент архитектуры ViewModel .

Кирилл Кармазин
источник
12

Ограничения памяти для каждого приложения указаны здесь в зависимости от размера экрана и версии Android: https://drive.google.com/file/d/0B7Vx1OvzrLa3Y0R0X1BZbUpicGc/view?usp=sharing

Источник: Загрузки для Android-совместимости http://source.android.com/compatibility/downloads.html ; Документ определения совместимости (CDD), раздел «Совместимость виртуальных машин» или «Совместимость во время выполнения»


источник
2
URL-адрес диска запрашивает разрешение на доступ
silent_grave