Задача довольно простая, т.к. в АПИ уже доступно всё необходимое. Раз уж мы коснёмся памяти, то давайте постараемся вывести максимальное количество информации.
Что будет уметь приложение:
- Вывод общей информации о состоянии памяти устройства
- Вывод общей информации о состоянии памяти выделенной приложению (процессу)
- Вывод детальной информации о состоянии памяти для процесса.
- (Как бонус) Вывод списка процессов на Андроид 4 – 5.
АПИ.
Вывод общей информации о состоянии памяти устройства.
Классы:
Методы:
- getMemoryInfo(ActivityManager.MemoryInfo outInfo) – данные метод вернёт нам объект типа «ActivityManager.MemoryInfo»
Класс «ActivityManager.MemoryInfo» содержит несколько полей и методов, нас интересуют поля:
- public long availMem – Объём свободной памяти доступной системе.
- public boolean lowMemory – Устанавливается в True, если система считает, что в данный момент времени памяти не хватает.
- public long threshold – Пороговое значение памяти для availMem, при котором, система начинается уничтожать фоновые службы и другие процессы.
- public long totalMem – Объём памяти устройства.
Все значения в байтах.
Код будет примерно таким:
procedure TFormMain.GetGeneralInfo; var ActivityManager: JActivityManager; MemoryInfo: JActivityManager_MemoryInfo; begin ActivityManager := TJActivityManager.Wrap (TAndroidHelper.Context.getSystemService(TJContext.JavaClass.ACTIVITY_SERVICE)); MemoryInfo := TJActivityManager_MemoryInfo.JavaClass.init; ActivityManager.getMemoryInfo(MemoryInfo); lvGeneralInfo.Items.Clear; AddHeaderInListView(lvGeneralInfo, 'API Info'); AddDataInListView(lvGeneralInfo, 'Total memory:', TUtils.FormatBytes(MemoryInfo.totalMem)); AddDataInListView(lvGeneralInfo, 'Available memory:', TUtils.FormatBytes(MemoryInfo.availMem)); AddDataInListView(lvGeneralInfo, 'Threshold:', TUtils.FormatBytes(MemoryInfo.threshold)); AddDataInListView(lvGeneralInfo, 'Low memory(?):', TUtils.BooleanToString(MemoryInfo.lowMemory)); end;
Вывод общей информации о состоянии памяти выделенной приложению (процессу).
В данной ситуации мы задействуем возможности языка JAVA, а точнее, воспользуемся классом «java.lang.Runtime (Oracle Docs)»(или «java.lang.Runtime (Android Docs)»).
Нас интересуют методы:
- static Runtime getRuntime() – Возвращает объект, связанный с текущим приложением
- long freeMemory() – Возвращает значение, характеризующее количество свободной памяти относительно «totalMemory()».
- long maxMemory() – Возвращает значение, характеризующее общее количество выделенной памяти для использования приложением.
- long totalMemory() – Возвращает значение, характеризующее количество выделенной памяти на текущий момент.
Все значения в байтах.
Также рассчитаем количество используемой памяти (Used memory) и количество свободной памяти (Total free memory) относительно «maxMemory()».
Картинка найдена и стырена со стековерфлоу.
Код будет примерно таким:
Код будет примерно таким:
procedure TFormMain.GetGeneralInfo; var Runtime: JRuntime; begin Runtime := TJRuntime.JavaClass.getRuntime; AddHeaderInListView(lvGeneralInfo, 'JVM Info (this process)'); AddDataInListView(lvGeneralInfo, 'Max memory:', TUtils.FormatBytes(Runtime.maxMemory)); AddDataInListView(lvGeneralInfo, 'Total allocated memory:', TUtils.FormatBytes(Runtime.totalMemory)); AddDataInListView(lvGeneralInfo, 'Used memory:', TUtils.FormatBytes(Runtime.totalMemory - Runtime.freeMemory)); AddDataInListView(lvGeneralInfo, 'Currently allocated free memory:', TUtils.FormatBytes(Runtime.freeMemory)); AddDataInListView(lvGeneralInfo, 'Total free memory:', TUtils.FormatBytes(Runtime.maxMemory - (Runtime.totalMemory - Runtime.freeMemory))); end;
Вывод детальной информации о состоянии памяти для процесса и (Как бонус) Вывод списка процессов на Андроид 4 – 5.
Вернёмся к Андроид АПИ. Эти два пункта я свяжу в один, чтобы не городить почти идентичный код два раза.
Важно! Также необходимо упомянуть причину указания версий Андроида для списка процессов. Причина проста, начиная с 5 версии Андроида, Гугл прикрыл лавочку по отображению списка всех процессов, метод будет возвращать только один процесс – это будет процесс вашего приложения. На некоторых 5 версиях, метод ещё работает. Также вы можете найти в интернете jar библиотеку, которая позволяет получить список процессов на всех 5 версиях Андроида (там используется обходной путь, который в след. версиях Андроида уже закрыт) и достаточно сильно обрезанную информацию о процессах. Но мы на этом не будем заострять внимание, т.к. нам важно научиться получать информацию именно о нашем приложении.
Начнём с получения списка процессов.
Нам снова понадобится класс:
и класс:
Методы:
- List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() – Возвращает список запущенных процессов, а точнее объектов с информацией о каждом процессе.
Важно! На текущий момент, при разборе данных из этого метода происходит утечка памяти. В QC давно уже сообщил, в своём приложении я использовал обходные пути (records и принудительное уменьшение счётчика ссылок). О том как я отловил эту утечку, я расскажу в след. статье.
Update 6.03.17 Не пытайтесь дебажить проект через RAD Studio, словите ошибку. Если очень хочется, то закомментируйте строчку "Process._Release;". Но имейте ввиду, что тогда будет происходить утечка памяти!
Класс «ActivityManager.RunningAppProcessInfo» содержит поля (в списке ниже, только те, которые я рассматриваю в этой статье):
- public int importance – Относительный уровень важности, который система даёт процессу. Содержит номер одной из констант этого класса. Подробности смотрите тут ActivityManager.RunningAppProcessInfo.html#importance
- public int importanceReasonCode – Основание для выдачи важности, если имеется.
- public int lru – Дополнительная подкатегория важности.
- public int pid – Идентификатор процесса. 0 если ни одного.
- public String processName – Название процесса.
- public int uid – Идентификатор пользователя этого процесса.
- Информацию об остальных полях вы можете почитать в справке ActivityManager.RunningAppProcessInfo.html#lfields
Теперь мы знаем идентификаторы всех процессов, а значит, можем получить детальную информацию о состоянии кучи (Heap) для каждого процесса.
Тот же класс, но другой метод:
- MemoryInfo[] getProcessMemoryInfo(int[] pids) – Возвращает информацию об использовании памяти одного или нескольких процессов.
Класс «android.os.Debug.MemoryInfo». Все методы и поля можно использовать. Для статьи и своего приложения я использую:
Методы:
Методы:
- int getTotalPrivateDirty()
- int getTotalPss()
- int getTotalSharedDirty()
Поля:
- public int dalvikPrivateDirty
- public int dalvikPss
- public int dalvikSharedDirty
- public int nativePrivateDirty
- public int nativePss
- public int nativeSharedDirty
- public int otherPrivateDirty
- public int otherPss
- public int otherSharedDirty
Все значения в килобайтах.
Пример кода смотрите на гитхабе, ссылка ниже.
Пример кода смотрите на гитхабе, ссылка ниже.
Моё приложение.
Приложение разработано на Delphi Berlin 10.1.2. Для приложения сделаны две дополнительные обёртки, для классов «java.lang.Process» и «java.lang.Runtime». Написано немного грубо, пока не было времени всё поправить.
Приложение разработано на Delphi Berlin 10.1.2. Для приложения сделаны две дополнительные обёртки, для классов «java.lang.Process» и «java.lang.Runtime». Написано немного грубо, пока не было времени всё поправить.