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

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

MemTotal: 94348 кБ MemFree: 5784 кБ

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

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

12 ответов

Решение

ВНИМАНИЕ: Этот ответ измеряет использование памяти / доступное УСТРОЙСТВА. Это НЕ то, что доступно для вашего приложения. Чтобы оценить, что делает ваше приложение и РАЗРЕШЕНО, используйте ответ разработчика 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.

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


Обычно вы хотите знать состояние кучи памяти, поскольку, если она использует слишком много памяти, вы получаете 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 ДО того, как это достигнет нуля.)

Это также то, что показывает инструмент использования памяти 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 хранит слишком много больших растровых изображений, но плохая новость заключается в том, что я не думаю, что можно обнаружить такой случай во время выполнения.

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

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;

}

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

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

Философия управления памятью в Linux гласит: "Свободная память - пустая трата памяти".

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

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

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

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

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

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

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

ссылка:

Этот метод 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() стоит дорого, поэтому вы можете переместить его код в класс.

Я посмотрел на 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.

      /** accurate value under limitation */
int getAccurateAppUsedMemory() {
    ActivityManager manager = context.getSystemService(Context.ACTIVITY_SERVICE);
    Debug.MemoryInfo info = manager.getProcessMemoryInfo(new int[]{Process.myPid()})[0];
    // Warning: there's a limitation of invocation frequency on Android Q or later
    return info.getTotalPss(); // in kB
}

/** approximate value without limitation */
int getApproximateAppUsedMemory() {
    Debug.MemoryInfo info = new Debug.MemoryInfo();
    Debug.getMemoryInfo(info);
    return info.getTotalPss(); // in kB
}

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

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

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

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 не используется?

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;
}
Другие вопросы по тегам