Как узнать текущее использование памяти в Android?


108

Я использовал / proc / meminfo и проанализировал ответ на команду, но результат показывает, что:

MemTotal: 94348 kB MemFree: 5784 kB

средства. он показывает, что свободной памяти всего 5 МБ. Возможно ли это с мобильным Android? На моем мобильном телефоне установлено всего 5-6 приложений, а другие задачи не выполняются. но все же эта команда показывает, что свободной памяти очень мало.

Может кто-нибудь прояснить это? или есть ли другой способ использования памяти в Android?


2
Вы пытаетесь узнать свободную память на устройстве или в приложении? Если на приложение, то его нужно рассчитывать на куче а-ля Debug.getNativeHeapFreeSize().
Игорь Ганапольский

1
Для вычисления свободной памяти (в оперативной памяти) , используя / Proc / MemInfo вы должны получить совокупность MemFree , буферов , Cached и SwapCached . Для этой цели Android предоставляет API, который работает на API 16 и на подопечных. Meminfo полезен, если вы ориентируетесь на более старые API.
AB

Ответы:


174

ВНИМАНИЕ: Этот ответ измеряет использование / доступную память УСТРОЙСТВА. Это НЕ то, что доступно вашему приложению. Чтобы измерить, что делает ваше приложение, и РАЗРЕШЕНО ли это делать, используйте ответ разработчика Android .


Документы по Android - ActivityManager.MemoryInfo

  1. команда parse / proc / meminfo. Вы можете найти справочный код здесь: Получить использование памяти в Android

  2. используйте приведенный ниже код и получите текущую оперативную память:

    MemoryInfo mi = new MemoryInfo();
    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    activityManager.getMemoryInfo(mi);
    double availableMegs = mi.availMem / 0x100000L;
    
    //Percentage can be calculated for API 16+
    double percentAvail = mi.availMem / (double)mi.totalMem * 100.0;

Расшифровка числа 0x100000L

1024 bytes      == 1 Kibibyte 
1024 Kibibyte   == 1 Mebibyte

1024 * 1024     == 1048576
1048576         == 0x100000

Совершенно очевидно, что число используется для преобразования байтов в мебибайт

PS: нам нужно рассчитать общую память только один раз. поэтому вызывайте точку 1 только один раз в своем коде, а затем после этого вы можете повторно вызывать код точки 2.


Я хочу проверить размер памяти. Что такое MemoryInfo?
Piraba 06

Пираба, Свой андроид API класс. Проверьте это здесь developer.android.com/reference/android/app/… .
Badal

@SanjayJoshi Это потому, что переменная availMem содержит память в байтах. 1024 байта равны 1 килобайту, а 1024 килобайта равны 1 мегабайту. Итак, 1024 * 1024 равно 1048576
Рольф ツ

2
Преобразуйте в удвоение выше, иначе процентAvail будет 0
blueether

1
@Rolf ツ извините, но 1024 байта равны одному Кибибайту, а 1024 Кибибита - одному MibiByte. Кило и Мега - десятичные префиксы. 1000 байт = 1 килобайт. Это тоже неверно объяснено в ответе.
JacksOnF1re

88

Это зависит от вашего определения того, какой запрос памяти вы хотите получить.


Обычно вам нужно знать состояние кучи памяти, поскольку, если она использует слишком много памяти, вы получаете OOM и вылетаете из приложения.

Для этого вы можете проверить следующие значения:

final Runtime runtime = Runtime.getRuntime();
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

Чем больше переменная usedMemInMB приближается к maxHeapSizeInMB, тем ближе availHeapSizeInMBк нулю, тем ближе вы получаете OOM. (Из-за фрагментации памяти вы можете получить OOM ДО того, как он достигнет нуля.)

Это также показывает инструмент использования памяти DDMS.


В качестве альтернативы, существует реальное использование ОЗУ, то есть то, сколько использует вся система - см. Принятый ответ, чтобы рассчитать это.


Обновление: поскольку Android O заставляет ваше приложение также использовать собственную оперативную память (по крайней мере, для хранения растровых изображений, что обычно является основной причиной огромного использования памяти), а не только кучу, все изменилось, и вы получаете меньше OOM (потому что куча больше не содержит растровых изображений, проверьте здесь ), но вы все равно должны следить за использованием памяти, если подозреваете, что у вас есть утечки памяти. В Android O, если у вас есть утечки памяти, которые должны были вызвать OOM в более старых версиях, кажется, что он просто выйдет из строя, и вы не сможете его поймать. Вот как проверить использование памяти:

val nativeHeapSize = Debug.getNativeHeapSize()
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize

Но я считаю, что лучше всего использовать профилировщик IDE, который отображает данные в реальном времени с помощью графика.

Итак, хорошая новость для Android O заключается в том, что намного сложнее получить сбои из-за OOM хранения слишком большого количества больших растровых изображений, но плохая новость заключается в том, что я не думаю, что возможно выявить такой случай во время выполнения.


РЕДАКТИРОВАТЬ: кажется Debug.getNativeHeapSize() со временем меняется, так как он показывает общий максимальный объем памяти для вашего приложения. Таким образом, эти функции используются только для профилировщика, чтобы показать, сколько использует ваше приложение.

Если вы хотите получить реальную общую и доступную собственную оперативную память, используйте это:

val memoryInfo = ActivityManager.MemoryInfo()
(getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(memoryInfo)
val nativeHeapSize = memoryInfo.totalMem
val nativeHeapFreeSize = memoryInfo.availMem
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize
Log.d("AppLog", "total:${Formatter.formatFileSize(this, nativeHeapSize)} " +
        "free:${Formatter.formatFileSize(this, nativeHeapFreeSize)} " +
        "used:${Formatter.formatFileSize(this, usedMemInBytes)} ($usedMemInPercentage%)")

Вот это да. Так просто, но так верно!
Ран

каково реальное использование памяти? так usedMemInMB в этом случае не является реальным использованием памяти приложением? Когда я использую этот код, он показывает мне, что используется примерно 50 МБ, но когда я захожу в настройки телефона и вижу там использование памяти, мое приложение показывает 100 МБ. почему такая разница?
Batmaci

1
@batmaci Heap-память - это лишь часть общего объема памяти, используемой приложением. Существует также использование собственной памяти, которая обычно используется для веб-страниц, игр и некоторых тяжелых целей. Обычно приложениям нужно смотреть только в динамическую память, потому что она довольно низкая по сравнению с оперативной памятью устройства, и если они ее достигнут, приложение выйдет из строя (даже если свободной оперативной памяти много).
разработчик Android

Это отличный фрагмент кода, очень полезный для проверки OOM, большое спасибо.
aolphn

@AlphaOF Спасибо, но на Android O все изменилось. Я обновил ответ, чтобы он соответствовал ситуации.
разработчик Android

29

Вот способ рассчитать использование памяти запущенным в данный момент приложением :

public static long getUsedMemorySize() {

    long freeSize = 0L;
    long totalSize = 0L;
    long usedSize = -1L;
    try {
        Runtime info = Runtime.getRuntime();
        freeSize = info.freeMemory();
        totalSize = info.totalMemory();
        usedSize = totalSize - freeSize;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return usedSize;

}

4
Это простой подход, но, как указано в документации, метод freeMemory () класса среды выполнения возвращает объем доступной памяти для текущей программы или приложения. Так что помните об этом при использовании.
Аксель Фатих

2
@Peter - Да, это «неправильно», потому что он отвечает на другой вопрос, чем был задан. С другой стороны, это «правильно» для того, что обычно необходимо знать разработчику приложения: редко имеет значение, каково общее состояние памяти на УСТРОЙСТВЕ - если пользователь запускал много приложений, ОС должна использовать большую часть его память - иначе это неэффективно. ОС должна знать, что дает принятый ответ, чтобы знать, когда начинать убивать приложения, которые не использовались в последнее время. Но программист приложения должен знать, что ЭТОТ ответ (и аналогичный ответ разработчика Android) говорит вам, а не runtime.maxMemory.
ToolmakerSteve

Эти решения просто работают с памятью, предоставленной приложению средой выполнения. Это не дает представления обо всей системной памяти, как того требует OP.
AB

На многих устройствах (например, Xiaomi) Runtime.freeMemory()возвращает 0 и Runtime.totalMemory()возвращает только выделенную в данный момент память.
артем

17

Другой способ (в настоящее время на моем G1 отображается 25 МБ свободного места):

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;

Привет, Алекс, большое спасибо за помощь! Еще 1 вопрос. Этот код дает мне доступную оперативную память. Я также хочу отобразить общий объем оперативной памяти. Как это получить?
Badal

@Badal Я не знаю Java API для этого. Придерживайтесь синтаксического анализа / proc / meminfo.
янченко 06

12

Философия управления памятью Linux такова: «Свободная память - это потраченная впустую память».

Я предполагаю, что следующие две строки покажут, сколько памяти находится в «Буферах» и сколько в «Кэшированных». Хотя между ними есть разница (пожалуйста, не спрашивайте, в чем эта разница :), они оба примерно в сумме составляют объем памяти, используемый для кеширования файловых данных и метаданных.

Намного более полезным руководством по освобождению памяти в системе Linux является free(1)команда; на моем рабочем столе он сообщает такую ​​информацию:

$ бесплатно -m
             общее количество используемых бесплатных общих буферов кэшировано
Мем: 5980 1055 4924 0 91 374
- / + буферы / кеш: 589 5391
Своп: 6347 0 6347

Строка +/- buffers / cache: - это волшебная строка, она сообщает, что у меня действительно есть около 589 мегабайт активно необходимой памяти для процессов и около 5391 мегабайт «свободной» памяти, в том смысле, что 91 + 374 мегабайта буферов / кэшированной памяти можно выбросить, если ее можно с большей выгодой использовать в другом месте.

(Моя машина работала около трех часов, почти ничего не делая, кроме stackoverflow, поэтому у меня так много свободной памяти.)

Если Android не free(1)входит в комплект поставки, вы можете сами посчитать с /proc/meminfoфайлом; Мне просто нравится free(1)выходной формат. :)


1
@ Игорь, тогда тебе захочется cat /proc/meminfo. Это гораздо более подробно, но MemFree. Buffers, и Cached, вероятно, самые важные строки.
sarnold

6

Я ссылаюсь на несколько работ.

ссылка:

Этот метод getMemorySize () возвращается MemorySize с общим и свободным объемом памяти.
Я не совсем верю этому коду.
Этот код тестируется на LG G3 cat.6 (v5.0.1)

    private MemorySize getMemorySize() {
        final Pattern PATTERN = Pattern.compile("([a-zA-Z]+):\\s*(\\d+)");

        MemorySize result = new MemorySize();
        String line;
        try {
            RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
            while ((line = reader.readLine()) != null) {
                Matcher m = PATTERN.matcher(line);
                if (m.find()) {
                    String name = m.group(1);
                    String size = m.group(2);

                    if (name.equalsIgnoreCase("MemTotal")) {
                        result.total = Long.parseLong(size);
                    } else if (name.equalsIgnoreCase("MemFree") || name.equalsIgnoreCase("Buffers") ||
                            name.equalsIgnoreCase("Cached") || name.equalsIgnoreCase("SwapFree")) {
                        result.free += Long.parseLong(size);
                    }
                }
            }
            reader.close();

            result.total *= 1024;
            result.free *= 1024;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    private static class MemorySize {
        public long total = 0;
        public long free = 0;
    }

Я знаю, что Pattern.compile () стоит дорого, поэтому вы можете переместить его код в член класса.


3

Я посмотрел на Android Source Tree.

Внутри com.android.server.am. ActivityManagerService.java (внутренняя служба, предоставляемая android.app. ActivityManager ).

public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
    final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
    final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
    outInfo.availMem = Process.getFreeMemory();
    outInfo.totalMem = Process.getTotalMemory();
    outInfo.threshold = homeAppMem;
    outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
    outInfo.hiddenAppThreshold = hiddenAppMem;
    outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
            ProcessList.SERVICE_ADJ);
    outInfo.visibleAppThreshold = mProcessList.getMemLevel(
            ProcessList.VISIBLE_APP_ADJ);
    outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
            ProcessList.FOREGROUND_APP_ADJ);
}

Внутри android.os. Process.java

/** @hide */
public static final native long getFreeMemory();

/** @hide */
public static final native long getTotalMemory();

Он вызывает метод JNI из android_util_Process.cpp

Вывод

MemoryInfo.availMem = MemFree + Кэшируется в / proc / meminfo.

Ноты

Общая память добавлена ​​на уровне API 16.


1

вы также можете использовать инструмент DDMS, который сам является частью Android SDK. он также помогает в выделении памяти для Java-кода и нативного кода c / c ++.


0
public static boolean isAppInLowMemory(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);

    return memoryInfo.lowMemory;
}

0
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

Странный код. Он возвращает MaxMemory - (totalMemory - freeMemory). Если freeMemory равно 0, тогда код вернет MaxMemory - totalMemory, поэтому он может быть больше или равен 0. Почему freeMemory не используется?


0

Вот еще один способ просмотреть использование памяти вашим приложением:

adb shell dumpsys meminfo <com.package.name> -d

Пример вывода:

Applications Memory Usage (kB):
Uptime: 2896577 Realtime: 2896577

** MEMINFO in pid 2094 [com.package.name] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     3472     3444        0        0     5348     4605      102
  Dalvik Heap     2349     2188        0        0     4640     4486      154
 Dalvik Other     1560     1392        0        0
        Stack      772      772        0        0
    Other dev        4        0        4        0
     .so mmap     2749     1040     1220        0
    .jar mmap        1        0        0        0
    .apk mmap      218        0       32        0
    .ttf mmap       38        0        4        0
    .dex mmap     3161       80     2564        0
   Other mmap        9        4        0        0
      Unknown       76       76        0        0
        TOTAL    14409     8996     3824        0     9988     9091      256

 Objects
               Views:       30         ViewRootImpl:        2
         AppContexts:        4           Activities:        2
              Assets:        2        AssetManagers:        2
       Local Binders:       17        Proxy Binders:       21
    Death Recipients:        7
     OpenSSL Sockets:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

Для общего использования памяти:

adb shell dumpsys meminfo

https://developer.android.com/studio/command-line/dumpsys#meminfo

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.