Tổn Thất Bộ Nhớ và Lỗi Tràn Bộ Nhớ Trong Android ( MEMORY LEAKS – OUTOF MEMORYE RROR IN ANDROID)
Tổn thất bộ nhớ (Memory leaks) trong Android là khá dễ dàng sảy ra. Rất nhiều nhà phát triển đã không nhận ra việc tổn thất bộ nhớ hàng ngày trong ứng dụng của họ. Bạn có lẽ không chú ý tới vấn đề này hoặc biết về sự tồn tại của nó. Cho đến khi bạn nhìn thấy một ngoại lệ như này java . lang . ...
Tổn thất bộ nhớ (Memory leaks) trong Android là khá dễ dàng sảy ra. Rất nhiều nhà phát triển đã không nhận ra việc tổn thất bộ nhớ hàng ngày trong ứng dụng của họ. Bạn có lẽ không chú ý tới vấn đề này hoặc biết về sự tồn tại của nó. Cho đến khi bạn nhìn thấy một ngoại lệ như này
java.lang.OutOfMemoryError: Failed to allocate a 4308492 byte allocation with 467872 free bytes and 456KB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988) at android.content.res.Resources.loadDrawableForCookie(Resources.java:2580) at android.content.res.Resources.loadDrawable(Resources.java:2487) at android.content.res.Resources.getDrawable(Resources.java:814) at android.content.res.Resources.getDrawable(Resources.java:767) at com.nostra13.universalimageloader.core.DisplayImageOptions.getImageOnLoading(DisplayImageOptions.java:134)
Cái gì đang sảy ra ?? Lỗi này có nghĩa là gì ?? Có phải ảnh bitmap trong ứng dụng quá lớn cho hệ thống Android ? Đó là những câu hỏi thường trực trong đầu bạn ngay trong thời điểm bận nhận được ngoại lệ như vậy. Khi bạn nhìn thấy những điều này trong Stack trace , có thể bạn dễ bị hiểu sai . Khi bạn nhận được lỗi OutOfMemoryError nó có nghĩa rất chung chung có 9 trong 10 lần bạn đang bị tổn thất bộ nhớ. Những lần đầu tiên tôi nhìn thấy ngoại lệ này, tôi đã rất bối dối và cứ nghĩ rằng ảnh bitmap của tôi quá lớn. Vậy tổn thất bộ nhớ là gì? Một thất bại trong một chương trình giải phỏng bộ nhớ , nguyên nhân làm giảm hiệu suất và thất bại A failure in a program to release discarded memory, causing impaired performance or failure. Tại sao tổn thất bộ nhớ lại sảy ra trong android ? Tổn thất bộ nhớ trong Android là khá dễ dàng sảy ra, cái này có lẽ là một phần của vấn đề. Vấn đề lớn nhất là Object Context. Mỗi app có một Context của ứng dụng getApplicationContext() . Mỗi Activity là 1 subclass của Context, Cái này lưu trữ thông tin liên quan đến Activity hiện tại. Tổn thất bộ nhớ của bạn sẽ được liên kết tới hoạt động bị tổn thất. Một công cụ trong việc giám sát bộ nhớ cho một ứng dụng android Memory Monitor * Android Memory Monitor đang chạy trên app bị tổn thất bộ nhớ *
Android Memory Monitor sau khi fix tổn thất bộ nhớ Như bạn có thể thấy trong hình đầu tiên, ứng dụng sẽ thể lấy lại một phần bộ nhớ đã được sử dụng. Nó sử dụng trên 300MB tại điểm cao nhất trước khi OutOfMemoryError xảy ra. Hình thứ hai cho thấy rằng trình thu gom rác trong ứng dụng đã hoạt động tốt và ứng ựng có thể lấy lại một phần bộ nhớ đã được sử dụng trước đó.
Làm Thế Nào Để Giảm Tổn Thất Bộ Nhớ ??
- Tránh gửi Object Context thêm cho những Activity or Fragment
- Không bao giờ lưu Context hoặc View trong các biến static . Đây là dấu hiệu đầu tiên cho việc tổn thất bộ nhớ
private static TextView textView; //DO NOT DO THIS private static Context context; //DO NOT DO THIS
- Luôn luôn unregister các listener trong các phương thức onPause()/ onDestroy() . Bào gồm các Android Listener, Location services hoặc các custom listener của bạn
- Không tham chiếu các Activity vào trong AsyncTasks hoặc các thread trong background.
- Sử dụng Application Context ( getApplicationContext() ) thay vì Context từ Activity
Làm Thế Nào Để Sửa Nó ?
Fix tổn thất bộ nhớ cần nhiều thời gian và thực hành lặp đi lặp lại. Tổn thất bộ nhớ là rất khó để theo dõi. Thật may mắn có một vài công cụ giúp bạn
- Mở Android Studio , mở Android Monitor Tab
- Chạy ứng dụng và chọn nó từ list của những ứng dụng sẵn sàng.
- Làm một vài thao tác trên app , thao tác thật nhiều
- Thủ thuật ở đây là bắt ứng dụng trước khi OutOfMemoryException xảy ra
- Click trên Memory Tab trong Android Monitor
- Bạn sẽ nhìn thấy một biểu đồ đẹp, trước khi được vẽ . Khi bạn sẵn sàng click vào "initiate GC"
- Click vào "Dump Java Heap" và chờ một vài giây. Điều này sẽ tạo ra file .hprof bạn có thể sử dụng để phân tích memory sử dụng
- Chạy dòng lệnh bên dưới để convert file .hprof từ Android Studio vào MAT
./hprof-conv path/file.hprof exitPath/heap-converted.hprof
- Sau khi convert, mở file in MAT. Chọn “Leak Suspects Report” and click finish.
- Click vào icon có 3 thanh màu xanh. Sau đó bạn sẽ nhìn thấy danh sách của các object mà đã dùng bộ nhớ.
- Nhìn thấy danh sách của các object có thể làm bạn bối dối , bạn có thể filter những object bởi name class , tôi đề nghị bạn lên nhập package name
- Bây giờ tôi có thể thấy rằng có 9 object VideoDetailActivity , cái này rõ ràng là không đúng và chúng tôi nên có duy nhất một object. Tìm những object đang tham chiếu đến VideoDetailActivity , click chuột phải trên item và lựa chọn “Merge Paths to Shortest GC Root” và sau đó click “exclude all phantom/weak/soft etc. references”.
- Từ những thông tin bên dưới, rõ ràng có DisplayListener đã được register nhưng chưa bao giờ được unregister Do đó tổn thất bộ nhớ đã được giải quyết bằng cách gọi unregister
DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); displayManager.unregisterDisplayListener(listener);
Không phải tất cả cát tổn thất bộ nhớ là được tìm thấy , có nhiều trường hợp rất khó để phát hiện . Nhưng tôi hi vọng rằng qua hướng dẫn này các bạn có thể tìm ra được nguyên nhân và cách giải quyết.