Giới thiệu
Bài viết này hướng dẫn cách lấy kích thước heap memory tối đa (maximum heap size) được cấp cho ứng dụng Android. Thông tin này hữu ích để tối ưu hóa bộ nhớ, tránh OutOfMemoryError, và quyết định chiến lược cache hình ảnh.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp"
tools:context=".MainActivity">
<Button
android:id="@+id/btnHeapSize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kiểm tra Heap Size" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
Bước 3: Code lấy Heap Size (src/MainActivity.java)
import androidx.appcompat.app.AppCompatActivity;
import android.app.ActivityManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.Objects;
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Button btnHeapSize;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
btnHeapSize = findViewById(R.id.btnHeapSize);
btnHeapSize.setOnClickListener(v -> showHeapInfo());
}
private void showHeapInfo() {
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
if (activityManager != null) {
// 1. Heap size tối đa cho app (MB)
int maxMemoryMb = activityManager.getMemoryClass(); // MB
// 2. Heap size lớn (large heap) - nếu manifest có android:largeHeap="true"
int largeMemoryMb = activityManager.getLargeMemoryClass(); // MB
// 3. Thông tin chi tiết runtime (Runtime API)
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory(); // Giới hạn heap (bytes)
long totalMemory = runtime.totalMemory(); // Heap hiện tại đã cấp (bytes)
long freeMemory = runtime.freeMemory(); // Free trong heap hiện tại (bytes)
long usedMemory = totalMemory - freeMemory; // Đang dùng (bytes)
String info = String.format(
"=== Heap Memory Info ===\n\n" +
"ActivityManager.getMemoryClass(): %d MB\n" +
"ActivityManager.getLargeMemoryClass(): %d MB\n\n" +
"Runtime.maxMemory(): %s\n" +
"Runtime.totalMemory(): %s\n" +
"Runtime.freeMemory(): %s\n" +
"Runtime.usedMemory(): %s\n\n" +
"Gợi ý: Giữ used memory < 50%% maxMemory để tránh OOM",
maxMemoryMb,
largeMemoryMb,
formatBytes(maxMemory),
formatBytes(totalMemory),
formatBytes(freeMemory),
formatBytes(usedMemory)
);
textView.setText(info);
}
}
private String formatBytes(long bytes) {
if (bytes < 1024) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(1024));
String unit = "KMGTPE".charAt(exp - 1) + "B";
return String.format("%.2f %s", bytes / Math.pow(1024, exp), unit);
}
}
Bước 4: Manifest (androidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:largeHeap="true"> <!-- QUAN TRỌNG: Yêu cầu large heap -->
<activity android:name=".MainActivity">
<intent-filter>
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn nút "Kiểm tra Heap Size" để xem thông tin bộ nhớ.
Giải thích các chỉ số
| Chỉ số | Nguồn | Ý nghĩa |
|---|---|---|
getMemoryClass() |
ActivityManager | Heap size tối đa mặc định cho app (MB). Thiết bị cũ: 16-24MB, mới: 128-512MB+. |
getLargeMemoryClass() |
ActivityManager | Heap size tối đa nếu android:largeHeap="true" trong Manifest. Thường 2-4x memoryClass. |
Runtime.maxMemory() |
Java Runtime | Giới hạn heap hiện tại của VM (bytes). Bằng memoryClass hoặc largeMemoryClass. |
Runtime.totalMemory() |
Java Runtime | Heap hiện tại đã cấp phát từ OS (bytes). Tăng dần khi cần. |
Runtime.freeMemory() |
Java Runtime | Phần trống trong heap hiện tại (bytes). |
android:largeHeap="true" - Khi nào nên dùng?
- ✅ App xử lý ảnh lớn (editor, camera, gallery).
- ✅ Game, AR/VR, ML on-device.
- ✅ Video editing, audio processing.
- ❌ App thông thường (CRUD, list, form) - KHÔNG cần.
- ❌ Để fix OOM do leak memory - phải fix leak chứ không tăng heap.
Cảnh báo khi dùng largeHeap
- GC (Garbage Collection) chậm hơn do heap lớn hơn.
- Tăng pressure lên hệ thống, có thể bị kill trước khi OOM.
- Không tăng heap size trên một số thiết bị (OEM giới hạn).
- Không đảm bảo không bị OOM - vẫn cần quản lý bộ nhớ tốt.
Công cụ debug bộ nhớ hiện đại
- Android Studio Profiler > Memory: Real-time heap allocation, GC events, leak detection.
- LeakCanary: Tự động detect memory leak trong dev.
- Debug.getNativeHeapAllocatedSize(): Native memory (Bitmap, Canvas, JNI).
Debug.getNativeHeapSize(),Debug.getNativeHeapFreeSize().
Best Practices quản lý bộ nhớ
// 1. Dùng LruCache cho bitmap cache LruCachebitmapCache = new LruCache (maxSizeKb) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount() / 1024; // Size in KB } }; // 2. Glide/Picasso/Coil tự handle cache, pooling, lifecycle // 3. Tránh leak: // - Không hold Context/Activity/View trong static field/thread // - Unregister listener/callback trong onDestroy // - Dùng WeakReference cho callback // 4. Bitmap: inSampleSize, inBitmap, recycle() (API < 19), decode bounds first
Kết luận
Heap size thay đổi tùy thiết bị, phiên bản Android, và cờ largeHeap. Luôn test trên thiết bị thấp cấu hình, dùng Profiler để monitor, và tối ưu trước khi bật largeHeap.