Як отримати поточне використання пам'яті в android?


108

Я використав / proc / meminfo та проаналізував відповідь команди. Однак результат показує, що:

MemTotal: 94348 kB MemFree: 5784 kB

засоби. це показує, що є лише 5 МБ вільної пам'яті. Чи можливо це з мобільним Android? На моєму мобільному пристрої встановлено лише 5-6 додатків, і жодне інше завдання не виконується. але ця команда показує, що вільної пам’яті дуже мало.

Хтось може це уточнити? чи є якийсь інший спосіб залучення пам'яті в андроїд?


2
Ви намагаєтеся бачити вільну пам'ять на пристрій чи на додаток? Якщо на додаток, то його потрібно обчислити на купі а-ля Debug.getNativeHeapFreeSize().
ІгорГанапольський

1
Для обчислення вільної пам'яті (в оперативній пам’яті) за допомогою / proc / meminfo ви повинні отримати сукупність MemFree , Buffers , Cached і SwapCched . Для цього існує API, який надає Android, який працює на 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, клас Android для Android. Перевірте це developer.android.com/reference/android/app/… .
Бадал

@SanjayJoshi Це тому, що змінна availMem містить пам'ять у байтах. 1024 байт дорівнює 1 кілобайт, а 1024 кілобайт - 1 мегабайта. Так 1024 * 1024 дорівнює 1048576
Рольф ツ

2
Перетворити на подвійний вище, інакше відсоток досяжності буде 0
синім

1
@Rolf ツ вибачте, але 1024 байтів дорівнює одному Kibibyte, а 1024 Kibibyte - одному 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 робить ваш додаток також використовувати вбудовану оперативну пам’ять (принаймні, для зберігання Bitmaps, що зазвичай є основною причиною величезного використання пам'яті), а не лише купу, все змінилося, і ви отримуєте менше OOM (тому що heap більше не містить растрових зображень, перевірте тут ), але все ж слідкуйте за використанням пам'яті, якщо ви підозрюєте, що у вас є витоки пам'яті. На 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%)")

Ого. Так просто, але так правдиво!
Ран

яке реальне використання пам'яті? настільки використовуванийMemInMB в цьому випадку не є реальним використанням пам'яті програми? Коли я використовую цей код, він показує, що використання моє 50 Мб, але коли я переходжу до налаштувань телефону і бачу використання пам'яті, моя програма показує 100 Мб. чому така різниця?
batmaci

1
Пам’ять @batmaci Heap - це лише частина загального використання пам'яті програми. Існує також використання вбудованої пам'яті, яка зазвичай використовується для веб-сторінок, ігор та деяких важких цілей. Зазвичай додатки потрібно дивитись лише на купі пам’яті, тому що вона досить низька в порівнянні з оперативною пам’яттю пристрою, і якщо вони дістануться до неї, додаток вийде з ладу (навіть якщо вільної оперативної пам’яті достатньо).
андроїд розробник

Це ідеальний фрагмент коду, дуже корисний для перевірки OOM, дуже дякую.
aolphn

@AlphaOF Дякую, але на Android O. все змінилося. Я оновив відповідь, щоб відповідати ситуації там.
андроїд розробник

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
Це простий підхід, але, як було зазначено в документації, метод класу Runtime freeMemory () повертає наявну пам'ять для поточної програми або програми. Тож пам’ятайте про це під час використання.
Аксель Фатих

2
@Peter - Так, це "неправильно", оскільки він відповідає на інше питання, ніж було задано. З іншого боку, це "правильно" для того, що зазвичай повинен знати розробник додатків: рідко має значення загальний стан пам'яті на УСТРОЙСТВІ - якщо користувач запустив безліч додатків, ОС повинна використовувати більшість його пам'ять - інакше вона неефективна. ОС має знати, що дає прийнята відповідь, щоб знати, коли почати вбивати додатки, які не використовувались останнім часом. Але програміст додатків повинен знати, що ця відповідь (і аналогічна відповідь розробника для Android) говорить вам проти runtime.maxMemory.
ToolmakerSteve

Це рішення просто працює на пам'яті, оголеній програмою Runtime. Це не дає уявлення про всю системну пам'ять, як цього вимагає ОП.
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 питання. Цей код дає мені доступну оперативну пам’ять. Я також хочу відображати Total RAM. Як це отримати?
Бадал

@Badal Я не знаю для цього API Java. Дотримуйтесь розбору / proc / meminfo.
Янченко

12

Філософія управління пам’яттю Linux - це «вільна пам’ять витрачається на пам'ять».

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

Набагато кориснішим посібником щодо вільної пам'яті в системі Linux є free(1)команда; на моєму робочому столі він повідомляє таку інформацію:

$ безкоштовно -м
             загальна кількість кешованих безкоштовних спільних буферів
Пам .: 5980 1055 4924 0 91 374
- / + буфери / кеш: 589 5391
Зміна: 6347 0 6347

Рядок +/- буфери / кеш-пам'ять: це магічна лінія, вона повідомляє, що я дійсно маю близько 589 мегів активно потрібної оперативної пам’яті та близько 5391 мега «вільної» пам’яті, в тому сенсі, що 91 + 374 мегабайти буферів / кешованої пам'яті можна викинути, якщо пам'ять можна було б вигідніше використовувати в іншому місці.

(Моя машина працювала близько трьох годин, і майже нічого не робила, крім stackoverflow, через що у мене стільки вільної пам'яті.)

Якщо Android не постачається free(1), ви можете зробити математику самостійно з /proc/meminfoфайлом; Мені просто подобається free(1)вихідний формат. :)


1
@Igor, тоді ти захочеш 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 Дерево.

Всередині 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.

Примітки

Загальна пам'ять додана в рівні 16 API.


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.