Câu hỏi Clueless Giới thiệu về (có thể) Rò rỉ bộ nhớ Android


Tôi đã đối mặt với một số khó chịu OutOfMemoryErrors, ngay cả sau khi đảm bảo rằng tất cả các Sơ đồ trang web của tôi đều được chia tỷ lệ đúng cách. Thực tế, vấn đề dường như không liên quan đến Bitmap, nhưng tôi có thể sai.

Đối với mục đích thử nghiệm và cách ly, tôi đã chuyển đổi giữa hai hoạt động (hãy gọi chúng là Chính và Danh sách) bằng cách sử dụng Ngăn điều hướng của tôi (không sử dụng nút quay lại). Tôi có thể thấy trong DDMS rằng bộ nhớ được cấp phát tăng khoảng 180 KB mỗi lần tôi quay trở lại.

Tôi đã thực hiện các bãi bộ nhớ và sử dụng MAT nhật thực để phân tích 3 điểm khác nhau theo thời gian:

Screen1

Screen2

Screen3

Tôi nghi ngờ rò rỉ bộ nhớ nhưng tôi không thể tìm ra nguyên nhân của nó. Theo các bãi chứa bộ nhớ, có vẻ như đó là "Phần còn lại" và java.lang.FinalizerReference tiếp tục tăng lên. Người dùng ở câu hỏi này cũng có rất nhiều FinalizerReferences trong bãi chứa bộ nhớ của mình, nhưng câu trả lời không hoàn toàn rõ ràng.

Báo cáo nghi ngờ rò rỉ tôi đã thực hiện ở thời điểm cuối cùng không hữu ích vì nó nghi ngờ android.content.res.Resources và android.graphics.Bitmap dường như không tăng theo thời gian:

Screen3LeakReport

Trong một trong các báo cáo (thật đáng buồn, không có mặt ở đây) Tôi đã thấy 13 trường hợp android.widget.ListView chỉ là một nghi ngờ rò rỉ tiềm tàng.

Sự gia tăng bộ nhớ này xảy ra với bất kỳ sự chuyển tiếp nào giữa các hoạt động (không chỉ chính và Danh sách tôi đã sử dụng trong ví dụ này).

Làm thế nào tôi có thể tìm thấy rò rỉ bộ nhớ (không rõ ràng?)? Tôi đã gãi đầu trong một thời gian dài nên mọi trợ giúp và mẹo đều tuyệt vời.

CHỈNH SỬA:

  • Ảnh bitmap (@ OrhanC1): Tôi đã nhận xét bất kỳ Bitmap instantiations trong hai hoạt động nêu trên và bộ nhớ vẫn tăng. Vùng nhớ bộ nhớ vẫn hiển thị một số bitmap nhưng tôi tin rằng chúng liên quan đến tài nguyên chứ không phải các bitmap thực được phân bổ bởi tôi.

  • Về phông chữ tùy chỉnh (@erakitin): Tôi đang sử dụng chúng, nhưng tôi giữ một ví dụ duy nhất của mỗi Typeface trong tôi Application bối cảnh (public class MyApp extends Application) bằng cách sử dụng một singleton. Tôi đã cố gắng bình luận bất kỳ tham chiếu đến các phông chữ trong hai hoạt động nêu trên và bộ nhớ vẫn tăng lên.

  • Tôi không nghĩ rằng tôi đang bị rò rỉ Context (@DigCamara): Tôi không giữ bất kỳ tham chiếu tĩnh nào bên trong hai Hoạt động này, tôi đang sử dụng Application bối cảnh thay vì Activityngoại trừ trong một adapter. Nếu tôi ở lại trong cùng một Activity và quay một số màn hình, bộ nhớ không tăng.

  • Dựa trên nhận xét của @ NickT: Tôi có thể thấy tôi có nhiều trường hợp của cả hai hoạt động. Những bộ nhớ này có thể tăng lên không chỉ là kết quả của việc tăng số lượng hoạt động của ngăn xếp lưng và không phải là rò rỉ bộ nhớ (Tôi mặc dù hệ điều hành đã xử lý điều đó, dường như không)? Nếu tôi sử dụng FLAG_ACTIVITY_REORDER_TO_FRONT ý định cờ sau đó bộ nhớ chỉ tăng cho đến khi tất cả các hoạt động khác nhau đã được khởi tạo (một lần). Hữu ích cho vấn đề này: Android không giết hoạt động từ ngăn xếp khi bộ nhớ yếu.


24
2018-05-14 10:51


gốc


Bạn có bắt đầu một phiên bản mới của hoạt động mỗi lần chuyển đổi (thay vì sử dụng lại một phiên bản nền) không? Có lẽ câu trả lời của tôi cho điều này có thể hữu ích: stackoverflow.com/questions/6835398 - NickT
Điều gì xảy ra khi bạn xóa hoàn toàn các ảnh bitmap? - OrhanC1
Nếu không nhìn thấy mã của bạn, chúng tôi chỉ có thể đoán những gì đang xảy ra. - Squonk
@Squonk - Tôi đồng ý với bạn nhưng trong trường hợp đặc biệt này phức tạp của nó: vì tôi không thực sự biết nguồn gốc của vấn đề tôi phải đăng một số lượng rất lớn của mã. - user1987392
@ OrhanC1 - Tôi đã nhận xét bất kỳ việc tạo Bitmap nào trong hai hoạt động được minh họa. Bộ nhớ vẫn tăng. - user1987392


Các câu trả lời:


Có vẻ như lý do tại sao Remainder đang phát triển là sự tăng trưởng của số lượng Activity các phiên bản trong ngăn xếp lại (ví dụ: 13 phiên bản của "Danh sách" Activity+ 13 phiên bản của "Main" Activity).

Tôi đã thay đổi Ngăn Điều hướng của mình để khi người dùng nhấp vào nút "Trang chủ" (đưa anh ta đến "Trang tổng quan" của Ứng dụng), tôi đã đặt Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK cờ: Hoạt động được sử dụng lại và ngăn xếp lại bị xóa (theo hướng dẫn của Android, thực ra). Trong thực tế, tôi nên đã làm điều này đã được như tôi không muốn một số trường hợp của bảng điều khiển ("Home") hoạt động được tạo ra.

Bằng cách này tôi có thể thấy rằng các hoạt động bị phá hủy và phân bổ kích thước heap (bao gồm cả "Remaining"slice" giảm:

Fixing problem with increasing memory.

Trong khi sửa lỗi này, tôi cũng nhận thấy rằng một trong các Hoạt động của tôi và một Bitmap được sử dụng bởi nó không bị phá hủy, ngay cả khi ngăn xếp lưng đã bị xóa (rò rỉ). Sau khi phân tích với MAT tôi kết luận rằng nguồn gốc của vấn đề phụ này là một tham chiếu đến ImageView mà tôi giữ trong Activity. Bằng cách thêm mã này vào onStop() phương pháp, tôi đã quản lý để có được cả hoạt động và Bitmap Bị phá hủy:

@Override
protected void onStop() {
    super.onStop();

    ImageView myImage = (ImageView) findViewById(R.id.myImage );
    if(myImage .getDrawable() != null)
        myImage.getDrawable().setCallback(null);

    RoundedImageView roundImage = (RoundedImageView) findViewById(R.id.roundImage); // a custom View
    if(roundImage.getDrawable() != null)
        roundImage.getDrawable().setCallback(null);


}

Sau đó tôi tổng quát tất cả Activity và FragmentActivity để họ gọi unbindDrawables(View view) trong onDestroy():

private void unbindDrawables(View view)
{
    if (view.getBackground() != null)
    {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup && !(view instanceof AdapterView))
    {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
        {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

Nhờ @NickT đã chỉ cho tôi đúng hướng.


10
2018-05-15 10:51