Giới thiệu
Bài viết hướng dẫn sử dụng ActivityManager.setWatchHeapLimit() để đặt ngưỡng theo dõi heap size. Khi heap của process vượt ngưỡng này, hệ thống sẽ ghi log cảnh báo. Dùng cho debug/profiling memory.
Các bước thực hiện
Bước 1: Tạo project mới
Android Studio → File → New Project → Empty Activity.
Bước 2: Giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<TextView
android:id="@+id/tvStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Heap watch limit set"
android:textSize="18sp" />
</LinearLayout>
Bước 3: Code (MainActivity.kt)
package com.example.setheapwatch
import android.app.ActivityManager
import android.content.Context
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
// Đặt giới hạn heap watch: 4 MB (4096 KB = 4,194,304 bytes)
// Tham số là BYTES
val limitBytes = 4 * 1024 * 1024 // 4MB
activityManager.setWatchHeapLimit(limitBytes)
tvStatus.text = "Đã đặt heap watch limit: ${formatBytes(limitBytes)}"
}
private fun formatBytes(bytes: Long): String {
return when {
bytes >= 1024 * 1024 -> "${bytes / (1024 * 1024)} MB"
bytes >= 1024 -> "${bytes / 1024} KB"
else -> "$bytes B"
}
}
}
Giải thích
setWatchHeapLimit(bytes: Long): Thiết lập ngưỡng heap (bytes). Khi heap allocated > ngưỡng, hệ thống log warning.- Đơn vị tham số: **Bytes** (không phải KB/MB).
clearWatchHeapLimit(): Xóa ngưỡng đã đặt.- Chủ yếu dùng trong **development/debugging** để phát hiện memory leak sớm.
⚠️ Lưu ý QUAN TRỌNG: Quyền hạn chế
App thông thường KHÔNG THỂ sử dụng API này.
- Cần quyền
android.permission.SET_ACTIVITY_WATCHER(protectionLevel: signature|privileged). - Chỉ **system apps** (pre-installed, signed với platform key) hoặc **root** mới được cấp quyền này.
- App user-installed sẽ bị
SecurityExceptionhoặc no-op silently.
Cách debug memory cho app thường (Thay thế)
1. Android Studio Profiler (Khuyên dùng nhất)
View → Tool Windows → Profiler → Memory tab. Theo dõi realtime: Java heap, Native heap, Graphics, Stack, Code, Others. Capture heap dump, record allocations.
2. Debug.MemoryInfo (App process memory)
val debugInfo = Debug.MemoryInfo()
Debug.getMemoryInfo(debugInfo)
Log.d("Memory", "Native Heap: ${debugInfo.nativeHeapAllocatedSize / 1024} KB")
Log.d("Memory", "Dalvik Heap: ${debugInfo.dalvikHeapAllocatedSize / 1024} KB")
3. ActivityManager.getProcessMemoryInfo()
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val pids = intArrayOf(android.os.Process.myPid()) val infos = am.getProcessMemoryInfo(pids) val pss = infos[0].totalPss // KB - Proportional Set Size (chuẩn đo memory thực)
4. LeakCanary (Library phát hiện leak tự động)
// build.gradle debugImplementation "com.squareup.leakcanary:leakcanary-android:2.12" // Tự động báo leak trong debug build
5. onTrimMemory() callback
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
when (level) {
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> { /* Clear UI caches */ }
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW -> { /* Reduce memory */ }
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> { /* Clear non-essential */ }
}
}