Ghi tệp báo lỗi để xem những đối tượng nào trong ứng dụng đang dùng hết bộ nhớ tại thời điểm ghi và xác định tình trạng rò rỉ bộ nhớ hoặc hành vi phân bổ bộ nhớ dẫn đến tình trạng giật, treo và thậm chí là sự cố ứng dụng. Việc tạo tệp báo lỗi đặc biệt hữu ích sau một phiên đăng nhập kéo dài của người dùng, khi tệp báo lỗi có thể cho thấy các đối tượng vẫn còn trong bộ nhớ mà đáng nhẽ không nên ở đó nữa.
Trang này mô tả các công cụ mà Android Studio cung cấp để thu thập và phân tích tệp báo lỗi. Ngoài ra, bạn có thể kiểm tra bộ nhớ của ứng dụng qua dòng lệnh bằng dumpsys
cũng như xem các sự kiện thu gom rác (GC) trong Logcat.
Tại sao bạn nên phân tích bộ nhớ ứng dụng
Android cung cấp một môi trường bộ nhớ được quản lý – khi nhận thấy ứng dụng của bạn không còn sử dụng một số đối tượng, trình thu gom rác sẽ giải phóng bộ nhớ không dùng đến trở về vùng nhớ khối xếp. Tuy Android liên tục cải tiến cách tìm bộ nhớ không dùng đến, nhưng đến một thời điểm nào đó trên mọi phiên bản Android, hệ thống sẽ phải tạm dừng mã của bạn trong giây lát. Trong hầu hết trường hợp, bạn sẽ không nhận thấy việc tạm dừng. Tuy nhiên, nếu ứng dụng của bạn phân bổ bộ nhớ nhanh hơn tốc độ hệ thống thu thập bộ nhớ, thì ứng dụng của bạn có thể bị gián đoạn trong khi trình thu gom giải phóng đủ bộ nhớ để đáp ứng mức phân bổ. Tình trạng trễ này có thể khiến ứng dụng của bạn bỏ qua khung hình cũng như làm chậm khung hình.
Ngay cả khi ứng dụng của bạn không bị chậm lại, nếu bị rò rỉ bộ nhớ, thì ứng dụng vẫn có thể giữ lại bộ nhớ đó ngay cả khi đang ở chế độ nền. Tình trạng này có thể làm giảm hiệu suất của bộ nhớ còn lại trong hệ thống do các sự kiện buộc thu thập rác không cần thiết. Cuối cùng, hệ thống buộc phải đóng quy trình ứng dụng để lấy lại bộ nhớ. Sau đó, khi người dùng quay lại ứng dụng của bạn, quy trình ứng dụng phải khởi động lại hoàn toàn.
Để biết thông tin về các phương pháp lập trình có thể làm giảm mức sử dụng bộ nhớ của ứng dụng, hãy đọc nội dung Quản lý bộ nhớ của ứng dụng.
Tổng quan về tệp báo lỗi
Để ghi tệp báo lỗi, hãy chọn tác vụ Analyze Memory Usage (Heap Dump) (Phân tích mức sử dụng bộ nhớ (Tệp báo lỗi)) (sử dụng Profiler: run 'app' as debuggable (complete data) (Trình phân tích: chạy "ứng dụng" ở chế độ có thể gỡ lỗi (dữ liệu đầy đủ))) để ghi tệp báo lỗi. Trong khi kết xuất vùng nhớ khối xếp, mức sử dụng bộ nhớ Java có thể tạm thời tăng lên. Hiện tượng này là bình thường vì tệp báo lỗi và ứng dụng của bạn diễn ra trong cùng một quy trình với ứng dụng, đồng thời cần có một lượng bộ nhớ để thu thập dữ liệu. Sau khi ghi tệp báo lỗi, bạn sẽ thấy nội dung sau:
Danh sách lớp hiển thị những thông tin sau:
- Allocations (Phân bổ): Số lượt phân bổ trong vùng nhớ khối xếp.
Native Size (Kích thước gốc): Tổng dung lượng bộ nhớ gốc mà loại đối tượng này sử dụng (tính bằng byte). Bạn sẽ thấy bộ nhớ ở đây cho một số đối tượng được phân bổ trong Java vì Android sử dụng bộ nhớ gốc cho một số lớp khung, chẳng hạn như
Bitmap
.Shallow Size (Kích thước của đối tượng): Tổng dung lượng bộ nhớ Java mà loại đối tượng này sử dụng (tính bằng byte).
Retained Size (Kích thước giữ lại): Tổng dung lượng bộ nhớ được giữ lại do tất cả các thực thể của lớp này (tính bằng byte).
Sử dụng trình đơn vùng nhớ khối xếp để lọc ra một số vùng nhớ khối xếp nhất định:
- Vùng nhớ khối xếp ứng dụng (mặc định): Vùng nhớ khối xếp chính nơi ứng dụng của bạn phân bổ bộ nhớ.
- Vùng nhớ khối xếp hình ảnh: Hình ảnh khởi động của hệ thống, chứa các lớp được tải trước trong thời gian khởi động. Mức phân bổ tại đây không bao giờ di chuyển hoặc biến mất.
- Zygote heap (bộ nhớ khối xếp zygote): Vùng nhớ khối xếp dạng ngầm sao chép (copy-on-write) nơi quy trình ứng dụng được phát triển nhánh qua hệ thống Android.
Sử dụng trình đơn thả xuống về cách sắp xếp để chọn cách sắp xếp các lượt phân bổ:
- Arrange by class (default) (Sắp xếp theo lớp (mặc định)): Nhóm tất cả lượt phân bổ dựa trên tên lớp.
- Arrange by package (Sắp xếp theo gói): Nhóm tất cả lượt phân bổ dựa trên tên gói.
Sử dụng trình đơn thả xuống lớp để lọc theo nhóm lớp:
- Tất cả các lớp (mặc định): Hiển thị tất cả các lớp, bao gồm cả các lớp từ thư viện và phần phụ thuộc.
- Hiện hoạt động/mảnh bị rò rỉ: Cho thấy các lớp đang gây ra rò rỉ bộ nhớ.
- Hiển thị các lớp dự án: chỉ hiển thị các lớp do dự án của bạn xác định.
Nhấp vào tên lớp để mở ngăn Instance (Thực thể). Mỗi thực thể được liệt kê lại có những thông tin sau đây:
- Depth (Chiều sâu): Số bước nhảy ngắn nhất từ gốc GC bất kỳ đến thực thể đã chọn.
- Native Size (Kích thước gốc): Kích thước của thực thể này trong bộ nhớ gốc. Cột này chỉ xuất hiện trên Android 7.0 trở lên.
- Shallow Size (Kích thước của đối tượng): Kích thước của thực thể này trong bộ nhớ Java.
- Retained Size (Kích thước giữ lại): Kích thước của bộ nhớ mà thực thể này chiếm ưu thế (theo sơ đồ ưu thế (dominator tree)).
Nhấp vào một thực thể để hiển thị Thông tin chi tiết về thực thể, bao gồm cả Trường và Tham chiếu. Các loại trường và tham chiếu phổ biến là các loại có cấu trúc , mảng và các loại dữ liệu gốc trong Java. Nhấp chuột phải vào một trường hoặc tệp tham chiếu để chuyển đến thực thể hoặc dòng liên kết trong mã nguồn.
- Trường: Hiển thị tất cả các trường trong thực thể này.
- Tham chiếu: Cho thấy mọi thông tin tham chiếu đến đối tượng được làm nổi bật trong thẻ Instance (Thực thể).
Tìm lỗi rò rỉ bộ nhớ
Để nhanh chóng lọc ra các lớp có thể liên quan đến lỗi rò rỉ bộ nhớ, hãy mở trình đơn thả xuống lớp rồi chọn Hiển thị hoạt động/mảnh bị rò rỉ. Android Studio hiển thị các lớp mà nó cho rằng cho biết lỗi rò rỉ bộ nhớ cho các thực thể Activity
và Fragment
trong ứng dụng của bạn. Các loại dữ liệu mà bộ lọc hiển thị bao gồm:
- Các thực thể
Activity
đã bị huỷ bỏ nhưng vẫn đang được tham chiếu. - Các thực thể
Fragment
không cóFragmentManager
hợp lệ nhưng vẫn đang được tham chiếu.
Xin lưu ý rằng bộ lọc có thể mang lại kết quả dương tính giả trong các trường hợp sau:
Fragment
được tạo nhưng chưa được sử dụng.Fragment
đang được lưu vào bộ nhớ đệm nhưng không thuộcFragmentTransaction
.
Để tìm rò rỉ bộ nhớ theo cách thủ công hơn, hãy duyệt qua danh sách lớp và thực thể để tìm các đối tượng có Kích thước giữ lại lớn. Hãy tìm lỗi rò rỉ bộ nhớ do nguyên nhân bất kỳ trong số sau:
- Các lượt tham chiếu kéo dài đến
Activity
,Context
,View
,Drawable
và các đối tượng khác có thể duy trì tham chiếu đến vùng chứaActivity
hoặcContext
. - Các lớp không tĩnh bên trong (chẳng hạn như
Runnable
) có thể chứa một thực thểActivity
. - Bộ nhớ đệm duy trì các đối tượng lâu hơn mức cần thiết.
Khi bạn phát hiện thấy rò rỉ bộ nhớ tiềm ẩn, hãy sử dụng thẻ Fields (Trường) và References (Tham chiếu) trong Instance Details (Thông tin chi tiết về thực thể) để chuyển đến thực thể hoặc dòng mã nguồn mà bạn quan tâm.
Kích hoạt rò rỉ bộ nhớ để kiểm thử
Để phân tích mức sử dụng bộ nhớ, bạn nên tạo áp lực cho mã nguồn ứng dụng và buộc rò rỉ bộ nhớ. Có một cách để tìm ra lỗi rò rỉ bộ nhớ trong ứng dụng là cho ứng dụng chạy một lúc trước khi kiểm tra vùng nhớ khối xếp. Các lỗi rò rỉ có thể dần lộ ra trên quá trình phân bổ trong vùng nhớ khối xếp. Tuy nhiên, rò rỉ càng ít thì bạn cần chạy ứng dụng càng lâu để thấy được nơi rò rỉ.
Bạn cũng có thể kích hoạt sự cố rò rỉ bộ nhớ theo một trong các cách sau:
- Liên tục xoay thiết bị từ chế độ dọc sang chế độ ngang rồi ngược lại nhiều lần trong khi ở nhiều trạng thái hoạt động. Việc xoay thiết bị thường có thể khiến ứng dụng rò rỉ đối tượng
Activity
,Context
hoặcView
do hệ thống tạo lạiActivity
và nếu ứng dụng của bạn tham chiếu đến một trong những đối tượng đó ở nơi khác, thì hệ thống không thu thập được rác của đối tượng đó. - Chuyển đổi giữa ứng dụng của bạn với một ứng dụng khác khi ở nhiều trạng thái hoạt động. Ví dụ: chuyển đến màn hình chính, sau đó quay lại ứng dụng.
Xuất và nhập bản ghi tệp báo lỗi
Bạn có thể xuất và nhập tệp báo lỗi vùng nhớ khối xếp từ thẻ Bản ghi trước đây trong trình phân tích tài nguyên. Android Studio lưu bản ghi dưới dạng tệp .hprof
.
Ngoài ra, để sử dụng một trình phân tích tệp .hprof
khác như jhat, bạn cần chuyển đổi tệp .hprof
từ định dạng Android sang định dạng tệp .hprof
của Java SE. Để chuyển đổi định dạng tệp, hãy sử dụng công cụ hprof-conv
được cung cấp trong thư mục {android_sdk}/platform-tools/
. Chạy lệnh hprof-conv
với hai đối số: tên tệp .hprof
ban đầu và vị trí để ghi tệp .hprof
đã chuyển đổi, bao gồm cả tên tệp .hprof
mới. Ví dụ:
hprof-conv heap-original.hprof heap-converted.hprof