Android sử dụng các cơ chế quản lý bộ nhớ như Low Memory Killer Daemon (lmkd), Pressure Stall Information (PSI) và Oom Adjustment (OomAdj) để tối ưu hóa việc tiêu thụ tài nguyên hệ thống. Dưới đây là một số điểm chính liên quan đến những thành phần này:
1. Kiến trúc của hệ thống
Hệ thống bao gồm nhiều thành phần tương tác với nhau để giám sát và quản lý tài nguyên bộ nhớ:
- Khởi động các thành phần: Khi các ứng dụng hoặc dịch vụ được khởi động, hệ thống sẽ tính toán giá trị OomAdj cho từng tiến trình.
- Truyền thông giữa các module: Giá trị OomAdj được gửi qua socket tới lmkd để lưu trữ và xử lý sau này khi cần thiết.
- Theo dõi áp lực bộ nhớ: Các file node /proc/pressure/memory giúp lmkd nhận biết trạng thái hệ thống hiện tại thông qua cơ chế epoll_wait và wake_up_interruptible.
- Quyết định giết tiến trình: Khi áp lực bộ nhớ cao, lmkd sẽ kiểm tra các tiến trình dựa trên giá trị OomAdj và quyết định tiến trình nào cần bị giết để giải phóng tài nguyên.
2. Mục đích thiết kế và thời điểm khởi động
2.1 Oom Adjuster
Oom Adjuster điều chỉnh các yếu tố như trạng thái tiến trình, mức độ điều chỉnh Oom và nhóm điều phối nhằm tối ưu hóa hiệu suất hệ thống.
2.2 LMKD
LMKD theo dõi trạng thái bộ nhớ của hệ thống và giết các tiến trình không cần thiết để giảm áp lực bộ nhớ.
2.3 PSI
PSI cung cấp thông tin về áp lực tài nguyên hệ thống, giúp phát hiện và xử lý các nút thắt cổ chai.
3. Ví dụ mã nguồn
Dưới đây là ví dụ mã nguồn minh họa cách lmkd và PSI hoạt động:
// Khởi tạo PSI
static int __init psi_proc_init(void) {
proc_mkdir("tension", NULL);
proc_create("tension/io", 0, NULL, &psi_io_fops_custom);
proc_create("tension/memory", 0, NULL, &psi_memory_fops_custom);
proc_create("tension/cpu", 0, NULL, &psi_cpu_fops_custom);
return 0;
}
module_init(psi_proc_init);
// Định nghĩa các hàm thao tác file
static const struct file_operations psi_memory_fops_custom = {
.open = psi_memory_open_custom,
.read = seq_read,
.llseek = seq_lseek,
.write = psi_memory_write_custom,
.poll = psi_fop_poll_custom,
.release = psi_fop_release_custom,
};
4. Quy trình cập nhật OomAdj từ Framework
Khi framework cần cập nhật giá trị OomAdj cho một tiến trình, nó sẽ gửi dữ liệu thông qua socket tới lmkd:
// Cập nhật OomAdj từ Java layer
ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
// Gửi dữ liệu qua socket
ByteBuffer buf = ByteBuffer.allocate(4 * 4);
buf.putInt(LMK_PROCPRIO_CUSTOM);
buf.putInt(pid);
buf.putInt(uid);
buf.putInt(amt);
writeLmkd(buf, null);
5. Quy trình kích hoạt giết tiến trình bởi lmkd
LMKD sử dụng các thông tin thu thập từ PSI và các file node để xác định khi nào cần giết một tiến trình:
static void mp_event_psi_custom(int data, uint32_t events, struct polling_params *poll_params) {
union meminfo mi_custom;
union vmstat vs_custom;
// Đọc thông tin từ file node
if (vmstat_parse(&vs_custom) < 0 || meminfo_parse(&mi_custom) < 0) {
ALOGE("Không thể phân tích vmstat hoặc meminfo!");
return;
}
// Xác định trạng thái tái lập lại
if (vs_custom.field.pgscan_direct > init_pgscan_direct) {
reclaim = DIRECT_RECLAIM_CUSTOM;
} else if (vs_custom.field.pgscan_kswapd > init_pgscan_kswapd) {
reclaim = KSWAPD_RECLAIM_CUSTOM;
}
// Xác định lý do giết tiến trình
if (kill_reason != NONE) {
struct kill_info ki = { .kill_reason = kill_reason };
find_and_kill_process(min_score_adj, &ki, &mi_custom, &wi, &curr_tm);
}
}