Question
Measure Android App and Device Memory Usage Programmatically
Question
How can an Android application programmatically determine how much memory it is using? Additionally, how can it retrieve the amount of memory currently available on the device?
Short Answer
You will learn the difference between your app's memory usage and device-wide available memory, how to query both with Android APIs, and why “free memory” is not the best health metric on Android.
Concept
Android memory measurements answer different questions:
- App memory usage: memory currently associated with your process. This is useful when investigating leaks, large images, caches, or out-of-memory crashes.
- Device available memory: memory Android can make available for work without being under memory pressure. This helps an app decide whether it should reduce optional work, such as preloading media.
- Per-app memory limit: the approximate heap budget assigned to your app class. This is useful context, but it is not a target to fill.
Android runs on Linux, whose memory manager deliberately uses unused RAM for file and system caches. Therefore, a device having little literally “free” RAM is normal. Prefer ActivityManager.MemoryInfo.availMem and lowMemory over treating free RAM as a problem.
For your own process, Debug.MemoryInfo provides detailed memory statistics, including PSS (Proportional Set Size). PSS shares the cost of shared pages between processes, so it is commonly useful for comparing a process's practical memory footprint over time.
Mental Model
Think of RAM as a shared workshop:
- Your app's memory is the amount of workspace and tools your team is currently using.
- Device available memory is the amount of workspace the workshop manager can provide before needing to clear stored materials.
- Cached files are materials placed nearby because they may be useful again. They occupy space, but the manager can clear them when another team needs room.
That is why “free memory” alone is misleading: memory used for cache is still reclaimable when needed.
Syntax and Examples
Use ActivityManager for device-wide memory information and Debug.getMemoryInfo() for the current process.
import android.app.ActivityManager;
import android.content.Context;
import android.os.Debug;
public final class MemoryStats {
private MemoryStats() { }
public static void logMemory(Context context) {
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// Memory associated with this app process.
Debug.MemoryInfo appMemory = new Debug.MemoryInfo();
Debug.getMemoryInfo(appMemory);
int appPssKb = appMemory.getTotalPss();
// Device-wide memory state.
ActivityManager.MemoryInfo deviceMemory = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(deviceMemory);
deviceMemory.availMem;
deviceMemory.lowMemory;
activityManager.getMemoryClass();
System.out.println( + appPssKb + );
System.out.println( + availableBytes + );
System.out.println( + lowMemory);
System.out.println( + heapLimitMb + );
}
}
Step by Step Execution
Consider this diagnostic method:
ActivityManager manager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo deviceInfo = new ActivityManager.MemoryInfo();
manager.getMemoryInfo(deviceInfo);
Debug.MemoryInfo appInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(appInfo);
long availableMb = deviceInfo.availMem / (1024L * 1024L);
int appPssKb = appInfo.getTotalPss();
getSystemService(...)obtains Android'sActivityManagerservice.new ActivityManager.MemoryInfo()creates an object that will receive device memory data.manager.getMemoryInfo(deviceInfo)fills that object.deviceInfo.availMemis the available memory in bytes, anddeviceInfo.lowMemoryindicates memory pressure.new Debug.MemoryInfo()creates an object for details about the current app process.
Real World Use Cases
- Image-heavy screens: Record app PSS before and after loading a photo feed to detect unexpectedly retained bitmaps.
- Media apps: When
lowMemoryis true, reduce artwork preloading or clear nonessential in-memory caches. - Diagnostic reports: Add app PSS, available memory, and heap limit to an internal bug report.
- Large imports: Avoid starting optional previews or concurrent import jobs when the device reports memory pressure.
- Performance testing: Compare memory readings across repeated navigation cycles to spot growth that may indicate a leak.
Real Codebase Usage
In production code, memory readings are usually used as signals, not as exact resource accounting.
Check for pressure before optional work
boolean isDeviceUnderMemoryPressure(Context context) {
ActivityManager manager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
manager.getMemoryInfo(info);
return info.lowMemory;
}
if (isDeviceUnderMemoryPressure(context)) {
imageCache.clearMemory();
return;
}
preloadNextImages();
Respond to Android's trim-memory callbacks
For cache management, lifecycle callbacks are usually more useful than polling memory values:
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level >= TRIM_MEMORY_RUNNING_LOW) {
imageCache.clearMemory();
}
}
Apps commonly combine these approaches:
- Use
onTrimMemory()to release caches when Android asks.
Common Mistakes
Treating available RAM as an error
// Not a reliable conclusion:
if (deviceInfo.availMem < 500 * 1024 * 1024) {
// The phone is broken or cannot run the app.
}
Android intentionally uses RAM for caching. Check deviceInfo.lowMemory and make optional work smaller rather than assuming a fixed number works on every device.
Mixing units
int availableMb = (int) deviceInfo.availMem / 1024 / 1024;
The cast can overflow before division on devices with large amounts of memory. Use long arithmetic:
long availableMb = deviceInfo.availMem / (1024L * 1024L);
Calling getMemoryInfo() as a leak detector
A single PSS reading cannot prove a memory leak. Take comparable readings after repeating the same flow, and use Android Studio Memory Profiler to inspect retained objects.
Assuming PSS equals Java heap size
PSS includes more than Java/Kotlin heap allocations, such as native allocations and shared memory portions. It is a process footprint metric, not a direct count of Java objects.
Comparisons
| Measurement or API | What it tells you | Unit | Best use |
|---|---|---|---|
Debug.MemoryInfo.getTotalPss() | Approximate practical memory footprint of this process, with shared pages apportioned | KB | Monitoring process growth and diagnostics |
ActivityManager.MemoryInfo.availMem | Memory currently available system-wide | bytes | Adaptive optional work |
ActivityManager.MemoryInfo.lowMemory | Whether the system is under low-memory conditions | boolean | Reducing or clearing caches |
ActivityManager.getMemoryClass() | Approximate per-app heap class limit | MB | Capacity planning and testing |
| Android Studio Memory Profiler |
Cheat Sheet
// Get ActivityManager
ActivityManager manager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// Device-wide state
ActivityManager.MemoryInfo device = new ActivityManager.MemoryInfo();
manager.getMemoryInfo(device);
long availableBytes = device.availMem;
boolean underPressure = device.lowMemory;
long thresholdBytes = device.threshold;
// Current process memory
Debug.MemoryInfo app = new Debug.MemoryInfo();
Debug.getMemoryInfo(app);
int pssKb = app.getTotalPss();
// App heap class limit
int heapLimitMb = manager.getMemoryClass();
// Bytes to MB
long mb = availableBytes / (1024L * 1024L);
availMemis bytes.
FAQ
How do I get my Android app's current memory usage?
Create Debug.MemoryInfo, call Debug.getMemoryInfo(memoryInfo), then read memoryInfo.getTotalPss(). The result is in kilobytes.
How do I get available RAM on Android?
Use ActivityManager.getMemoryInfo(), then read MemoryInfo.availMem. The result is in bytes.
Does Android require a permission to read memory information?
No special permission is needed for the current process information and the device memory state shown here.
Is low free RAM bad on Android?
Not necessarily. Android uses spare RAM for caches and can reclaim cache memory. lowMemory is more meaningful than a literal free-memory number.
What is PSS in Android memory usage?
PSS means Proportional Set Size. It counts private process memory plus a proportional share of memory pages shared with other processes.
Can I use getMemoryClass() as my app's exact memory limit?
No. It is an approximate heap class limit and should not be treated as a target allocation size. Actual behavior varies with the device and the type of memory being allocated.
What should an app do when memory is low?
Release recreatable caches, stop optional preloading, and respond to onTrimMemory(). Do not kill your own process as a normal memory-management strategy.
Mini Project
Description
Build a small memory diagnostics helper for a debug screen or internal log. It gathers the current process PSS, device available memory, low-memory state, and the app heap class limit in a readable report.
Goal
Create a method that returns a formatted memory report and identifies whether the device is under memory pressure.
Requirements
Requirement 1
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.