Memory Leak Pattern in Android - Identification & Prevention

What is a memory leak?

Mọi ứng dụng đều cần bộ nhớ để thực hiện công việc của nó. Để đảm bảo mỗi ứng dụng trong Android có đủ bộ nhớ, hệ thống Android cần phải quản lý phân bổ bộ nhớ một cách hiệu quả. Android kích hoạt Garbage Collection - GC khi bộ nhớ chạy. Mục đích của GC là thu hồi bộ nhớ bằng cách xóa tất cả những object không còn được sử dụng đến. GC sẽ thực hiện theo 3 bước sau:

  1. Xem xét tất cả các tham chiếu object trong bộ nhớ từ GC root và đánh dấu các đối tượng đang hoạt động có tài liệu tham khảo từ GC root.
  2. Tất cả các object không được đánh dấu (garbages) đều bị xóa khỏi bộ nhớ.
  3. Sắp xếp lại những live object Nói tóm lại, tất cả mọi thứ phục vụ người dùng phải được lưu giữ trong bộ nhớ và mọi thứ khác sẽ bị xoá khỏi bộ nhớ để giải phóng tài nguyên. Tuy nhiên, khi code được viết một cách thoải mái và các đối tượng không sử dụng được tham chiếu một cách nào đó từ các đối tượng có thể truy cập, GC sẽ đánh dấu các đối tượng không sử dụng như là đối tượng có tham chiếu và do đó sẽ không thể xoá chúng. Đây được gọi là Memory leak.

How to identify a leak?

  1. Leak Canary: từ Square là một công cụ tốt để phát hiện leak trong ứng dụng của bạn. Nó tạo ra các tham chiếu yếu đến các hoạt động trong ứng dụng của bạn ( bạn cũng có thể tùy chỉnh nó bằng cách thêm theo dõi vào bất kỳ đối tượng nào khác ). Sau đó kiểm tra nếu tài liệu tham khảo được xóa sau khi GC. Nếu không, nó bỏ vào một tập tin .hprof và phân tích nó để xác nhận nếu có leak. Nếu có, nó sẽ hiển thị một thông báo và trong một ứng dụng riêng biệt, nó sẽ hiển thị cây tham chiếu về leak xảy ra như thế nào. Việc cài đặt Leak Canary rất đơn giản và nó giúp các nhà phát triển và QA tìm ra rò rỉ bộ nhớ trước khi ứng dụng của bạn đến tay người dùng của bạn.
  2. Android Studio: có một công cụ hữu ích để phát hiện leak. Bước 1: Compile and build debug. Bước 2: Đi đến hoạt động đáng ngờ, sau đó quay trở lại hoạt động trước đó sẽ kích hoạt hoạt động đáng ngờ từ ngăn xếp công việc. Bước 3: Trong Android Studio -> Màn hình Android Monitor -> Phần bộ nhớ, nhấp Initiate GC, sau đó nhấp vào nút Dump Java Heap. Bước 4: Khi nhấn nút Dump Heap của Java, Android Studio sẽ mở tệp tin hprof bị loại. Trong trình xem tệp hprof, có một vài cách bạn có thể kiểm tra rò rỉ bộ nhớ. Bạn có thể sử dụng công cụ Analyzer Tasks trên bảng điều khiển bên phải để phát hiện hoạt động bị rò rỉ tự động. Hoặc bạn có thể chuyển chế độ xem sang Package Tree View ở bên trên bên trái, tìm đến package của bạn. Kiểm tra **Total Count **của đối tượng hoạt động. Nếu có 1 hoặc nhiều trường hợp, có nghĩa là bị leak. Bước 5: Một khi bạn tìm thấy Hoạt động bị rò rỉ, hãy kiểm tra cây tham chiếu ở dưới cùng và tìm ra đối tượng nào đang tham chiếu đến hoạt động đã chết.

What are the common memory leak patterns that we need to prevent ?

Có rất nhiều trường hợp gây ra memory leak, nhưng có thể loại bỏ bằng cách chú ý và tránh sử dụng không đúng. Dưới dây là 3 mục chính:

  • Leak activity to a static reference
  • Leak activity to a worker thread
  • Leak thread itself Và một số chú ý:
  • Unregistered listeners: Có nhiều tình huống mà bạn đăng ký một receiver nhưng quên hủy đăng ký. Điều này có thể dễ dàng dẫn đến memory leak rất lớn. Nói chung, nếu bạn đăng ký một nơi nào đó bạn cũng cần phải hủy đăng ký ngay ở đó.
  • Bitmaps: Những đối tượng bitmap nói chung khá nặng và nếu chúng được xử lý không đúng cách có thể dẫn đến leak đáng kể và bị OutOfMemoryError. Bộ nhớ bitmap liên quan đến tài nguyên hình ảnh mà bạn sử dụng trong ứng dụng của bạn sẽ tự động được quản lý bởi khung công tác, nhưng nếu bạn đang xử lý các bitmap bằng tay, hãy chắc chắn để recycle() chúng sau khi sử dụng. Bạn nên tải các bitmap lớn bằng cách mở rộng chúng, và sử dụng bộ nhớ đệm bitmap và pooling bất cứ khi nào có thể để giảm sử dụng bộ nhớ.
  • Contexts: Một lý do phổ biến khác khiến memory leak là lạm dụng của các trường hợp Context. Context chỉ đơn giản là một lớp trừu tượng. Có nhiều lớp (như Activity, Application, Service, v.v.) mở rộng để cung cấp các chức năng riêng của chúng. Điều rất quan trọng là phải hiểu được sự khác biệt giữa Activity Context và Application Context và cái gì nên được sử dụng trong những trường hợp nào. Sử dụng ở vị trí sai có thể giữ một tham chiếu đến toàn bộ Activity và gây ra memory leak.