Как узнать, сколько памяти использует моё Android-приложение?
Определение использования памяти в Android через Java API
Для измерения памяти вашего приложения в Android есть несколько встроенных инструментов. Основной способ — использовать класс Debug и Runtime из стандартной библиотеки Java. Вот как это сделать правильно.
1. Получение общей выделенной памяти (Heap Size)
Используйте Runtime.getRuntime() для получения информации о куче Java:
public class MemoryUtils {
public static void printMemoryInfo() {
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory(); // текущий размер кучи
long freeMemory = runtime.freeMemory(); // свободная память в куче
long usedMemory = totalMemory - freeMemory; // используемая память
long maxMemory = runtime.maxMemory(); // максимальный размер кучи
Log.d("Memory", "Total: " + totalMemory / 1024 / 1024 + " MB");
Log.d("Memory", "Free: " + freeMemory / 1024 / 1024 + " MB");
Log.d("Memory", "Used: " + usedMemory / 1024 / 1024 + " MB");
Log.d("Memory", "Max: " + maxMemory / 1024 / 1024 + " MB");
}
}
2. Получение памяти через Debug API (более точный способ)
Метод Debug.getMemoryInfo() даёт детальную статистику, включая память native и dalvik:
import android.os.Debug;
import android.os.Debug.MemoryInfo;
public class MemoryMonitor {
public static void logDetailedMemory() {
MemoryInfo memoryInfo = new MemoryInfo();
Debug.getMemoryInfo(memoryInfo);
Log.d("Memory", "Dalvik PSS: " + memoryInfo.dalvikPss + " KB");
Log.d("Memory", "Native PSS: " + memoryInfo.nativePss + " KB");
Log.d("Memory", "Total PSS: " + memoryInfo.getTotalPss() + " KB");
Log.d("Memory", "Total Private Dirty: " + memoryInfo.getTotalPrivateDirty() + " KB");
}
}
3. Решение вашей проблемы с кэшем изображений
Ваш код с static List<Bitmap> — классическая утечка памяти. Bitmap'ы могут занимать десятки мегабайт, и они никогда не освобождаются. Вот исправленная версия с использованием LruCache (из Android Support Library):
import android.util.LruCache;
public class ImageCache {
private static LruCache<String, Bitmap> cache;
static {
// Максимальный размер кэша — 1/8 от доступной памяти
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
cache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// Возвращаем размер Bitmap в килобайтах
return bitmap.getByteCount() / 1024;
}
};
}
public static void addImage(String url, Bitmap bitmap) {
if (bitmap != null) {
cache.put(url, bitmap);
}
}
public static Bitmap getImage(String url) {
return cache.get(url);
}
// Метод для проверки текущего размера кэша
public static void logCacheStatus() {
Log.d("Cache", "Current size: " + cache.size() + " KB");
Log.d("Cache", "Max size: " + cache.maxSize() + " KB");
}
}
4. Как использовать мониторинг в Activity
Добавьте логирование в ключевые точки вашего приложения:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Логируем память до загрузки
MemoryMonitor.logDetailedMemory();
// Используем LruCache вместо статического списка
Bitmap bitmap = loadBitmapFromUrl("https://example.com/image.jpg");
ImageCache.addImage("image1", bitmap);
ImageCache.logCacheStatus();
ImageView imageView = findViewById(R.id.imageView);
imageView.setImageBitmap(bitmap);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Логируем память после уничтожения Activity
MemoryMonitor.logDetailedMemory();
}
}
Рекомендации по предотвращению утечек:
- Не используйте статические ссылки на Context, Activity или Bitmap — это блокирует сборщик мусора.
- Всегда очищайте кэш при нехватке памяти. Переопределите
onTrimMemory()в вашем Application классе. - Используйте WeakReference для колбэков и слушателей.
- Для больших изображений применяйте библиотеки вроде Glide или Picasso — они автоматически управляют памятью.
Альтернативный подход: использование Android Studio Profiler и командной строки
Если вам нужен не программный, а внешний мониторинг, воспользуйтесь встроенным профилировщиком Android Studio или утилитой dumpsys.
1. Android Studio Profiler
Запустите приложение на устройстве или эмуляторе, откройте вкладку "Profiler" (View → Tool Windows → Profiler). Выберите ваше приложение и перейдите на вкладку "Memory". Вы увидите:
- График использования памяти в реальном времени.
- Количество выделенных объектов (Java heap, Native heap, Stack, Code).
- Кнопку "Dump Java Heap" для создания дампа кучи.
Дамп кучи можно открыть в Android Studio и найти объекты, которые не должны быть в памяти (например, старые Activity).
2. Командная строка (ADB)
Используйте команду dumpsys meminfo для получения детальной информации:
# Получить PID вашего приложения
adb shell ps | grep com.yourpackage
# Посмотреть память по PID
adb shell dumpsys meminfo [PID]
# Или по имени пакета
adb shell dumpsys meminfo com.yourpackage
Вывод покажет PSS (Proportional Set Size) для каждого компонента: Dalvik, Native, Graphics, и т.д. Обратите внимание на раздел "Views" и "Activities" — если количество Activity растёт, это признак утечки.
3. Автоматизация с помощью Shell-скрипта
Напишите простой скрипт для периодического снятия показаний:
#!/bin/bash
PACKAGE="com.example.myapp"
while true; do
adb shell dumpsys meminfo $PACKAGE | grep "TOTAL"
sleep 5
done
Этот метод удобен для тестирования в цикле, когда вы выполняете определённые действия в приложении.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги