Những công cụ và phương pháp Android nào hoạt động tốt nhất để tìm rò rỉ bộ nhớ / tài nguyên? [đóng cửa]


152

Tôi đã phát triển một ứng dụng Android và tôi đang ở thời điểm phát triển ứng dụng điện thoại nơi mọi thứ dường như đang hoạt động tốt và bạn muốn tuyên bố chiến thắng và giao hàng, nhưng bạn biết rằng phải có một số rò rỉ về bộ nhớ và tài nguyên trong đó; và chỉ có 16mb heap trên Android và nó dễ bị rò rỉ một cách đáng ngạc nhiên trong một ứng dụng Android.

Tôi đã tìm kiếm xung quanh và cho đến nay chỉ có thể tìm hiểu thông tin về 'hprof' và 'traceview' và không nhận được nhiều đánh giá thuận lợi.

Những công cụ hoặc phương pháp nào bạn đã gặp hoặc phát triển và quan tâm để chia sẻ có thể trong một dự án hệ điều hành?


3
Tôi có thể bỏ phiếu để thay đổi tên của mình thành một thứ mà con người có thể đọc được không.
JPM

1
Bạn có thể mở lại câu hỏi này không nếu chúng tôi xóa từ "Công cụ Android" khỏi tiêu đề câu hỏi? Các câu trả lời được tìm thấy ở đây khá hữu ích để giải quyết các vấn đề rò rỉ bộ nhớ của tôi
k3b

Được rồi, vì vậy tôi có một người dùng liên tục chuyển đổi giữa các hoạt động, có nghĩa là họ có thể đã chuyển 15 hoạt động trong 20 giây. Đó có thể là một nguyên nhân gây ra lỗi bộ nhớ? Tôi nên làm gì để khắc phục nó? Cảm ơn!
Ruchir Baronia

1
Không thể cung cấp câu trả lời này vì câu hỏi đã bị đóng, tuy nhiên tôi khuyên bạn nên xem Leak Canary . Chỉ cần sử dụng ứng dụng của bạn, mở và đóng các hoạt động và để thư viện thực hiện công việc đó. Nó thậm chí sẽ cho bạn biết nơi rò rỉ xảy ra. Chỉ cần cung cấp cho bộ phân tích rò rỉ một thời gian để thực hiện công việc của nó sau khi rò rỉ xảy ra - thường mất khoảng 2 phút hoặc hơn cho đến khi tìm thấy nguồn rò rỉ. Sau đó, nó sẽ trình bày cho bạn gọn gàng trong ứng dụng. Không có công cụ bổ sung cần thiết!
ubuntudroid

Câu trả lời:


90

Một trong những lỗi phổ biến nhất mà tôi thấy khi phát triển Ứng dụng Android là lỗi java.lang.OutOfMemoryError: Kích thước bitmap vượt quá lỗi VM ngân sách. Tôi đã phát hiện ra lỗi này một cách ngẫu nhiên đối với các hoạt động sử dụng nhiều bitmap sau khi thay đổi hướng: Hoạt động bị hủy, được tạo lại và các bố cục được thổi phồng từ XML sử dụng bộ nhớ VM có thể sử dụng cho bitmap.

Bitmap trên bố trí hoạt động trước đó không được bộ thu gom xử lý đúng cách vì chúng đã vượt qua các tham chiếu đến hoạt động của chúng. Sau nhiều thí nghiệm tôi đã tìm thấy một giải pháp khá tốt cho vấn đề này.

Đầu tiên, hãy đặt thuộc tính Id id trên chế độ xem chính của bố cục XML của bạn:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

Sau đó, trên phương thức onDestroy () của Hoạt động của bạn, hãy gọi phương thức unbindDrawables () chuyển một giới thiệu đến Chế độ xem cha và sau đó thực hiện System.gc ()

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

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}


private void unbindDrawables(View view) {

    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }

    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }

        ((ViewGroup) view).removeAllViews();
    }
}

Phương thức unbindDrawables () này khám phá cây xem đệ quy và:

  1. Loại bỏ các cuộc gọi lại trên tất cả các drawables nền
  2. Loại bỏ trẻ em trên mỗi nhóm xem

3
Giải pháp tốt cho một vấn đề chung.
While-E

9
Điều này không hoạt động đối với các lớp con của AdView (ListView, GridView, v.v.).
Arjun

@Arjun Có..tôi không hoạt động cho các lớp con Adaptor. Cho rằng bạn cần xử lý ngoại lệ. Nghỉ ngơi nó hoạt động tốt. Đó là những gì tôi sử dụng trong mã của mình và nó hoạt động tốt. Hi vọng điêu nay co ich.
hp.android

@ hp.android Bằng cách "xử lý trường hợp ngoại lệ" này, bạn có ví dụ nào về giao diện của nó không? Tôi hỏi bởi vì tôi có các trang hình ảnh trong tôi PageAdaptervà tôi đang khắc phục lỗi này :(
Jacksonkr

4
@Jackson chỉ cần thay đổi điều kiện: if (xem instanceof ViewGroup && (xem instanceof AdapterView)!) Này sẽ thoát khỏi ngoại lệ mà bạn đang nhận được cho Adaptor
hp.android


28

Chủ yếu dành cho khách du lịch Google đến từ tương lai:

Hầu hết các công cụ java không may không phù hợp với nhiệm vụ này, vì chúng chỉ phân tích JVM-Heap. Mọi ứng dụng Android cũng có một đống riêng, tuy nhiên, cũng phải phù hợp trong giới hạn ~ 16 MB. Nó thường được sử dụng cho dữ liệu bitmap, ví dụ. Vì vậy, bạn có thể chạy khá dễ dàng vào các lỗi Out Of Memory mặc dù JVM-Heap của bạn là chillin khoảng 3 MB, nếu bạn sử dụng nhiều drawable.


6
bắt đầu các bản vẽ Android 3.0 (tổ ong) được lưu trữ trong heap
Gu1234

@Timo thì bạn sẽ dùng gì để phát hiện rò rỉ trong heap riêng?
sydd

1
Kiểm tra, rất nhiều thử nghiệm. Vấn đề là bạn thậm chí không thể thực sự biết được ứng dụng của mình đang sử dụng bao nhiêu bộ nhớ, do chia sẻ bộ nhớ và các kỹ thuật tối ưu hóa khác. Bạn có thể nhận được đọc bộ nhớ bằng cách sử dụng các lệnh shell thông thường, nhưng đó là những ước tính rất, rất thô.
Timo Ohr

20

Câu trả lời từ @ hp.android hoạt động tốt nếu bạn chỉ làm việc với nền bitmap, nhưng trong trường hợp của tôi, tôi đã BaseAdaptercung cấp một bộ ImageViews cho a GridView. Tôi đã sửa đổi unbindDrawables()phương pháp theo lời khuyên để điều kiện là:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

nhưng vấn đề sau đó là phương pháp đệ quy không bao giờ xử lý con của AdapterView. Để giải quyết vấn đề này, tôi thay vào đó đã làm như sau:

if (view instanceof ViewGroup) {
  ViewGroup viewGroup = (ViewGroup) view;
  for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

  if (!(view instanceof AdapterView))
    viewGroup.removeAllViews();
}

để những đứa trẻ AdapterViewvẫn được xử lý - phương pháp không cố gắng loại bỏ tất cả trẻ em (không được hỗ trợ).

Điều này không khắc phục được vấn đề tuy nhiên vì ImageViews quản lý một bitmap không phải là nền tảng của chúng. Do đó tôi đã thêm vào như sau. Nó không lý tưởng nhưng nó hoạt động:

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

Nhìn chung, unbindDrawables()phương pháp là:

private void unbindDrawables(View view) {
  if (view.getBackground() != null)
    view.getBackground().setCallback(null);

  if (view instanceof ImageView) {
    ImageView imageView = (ImageView) view;
    imageView.setImageBitmap(null);
  } else if (view instanceof ViewGroup) {
    ViewGroup viewGroup = (ViewGroup) view;
    for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

    if (!(view instanceof AdapterView))
      viewGroup.removeAllViews();
  }
}

Tôi hy vọng có một cách tiếp cận nguyên tắc hơn để giải phóng các tài nguyên đó.


12

Trò chuyện I / O tốt của Google (2011) về Quản lý bộ nhớ trong Android, cũng như chi tiết về các công cụ + kỹ thuật để định hình bộ nhớ:
http://www.youtube.com/watch?v=_CruQY55HOk


4
Hoặc các bài viết trên blog tương ứng: android-developers.blogspot.com/2011/03/...
greg7gkb

1
Được rồi, vì vậy tôi có một người dùng liên tục chuyển đổi giữa các hoạt động, có nghĩa là họ có thể đã chuyển 15 hoạt động trong 20 giây. Đó có thể là một nguyên nhân gây ra lỗi bộ nhớ? Tôi nên làm gì để khắc phục nó? Cảm ơn!'
Ruchir Baronia


1

Chà, đó là những công cụ liên kết với các định dạng duy nhất mà Android sử dụng..Tôi nghĩ điều bạn có thể không hài lòng là khung mã kiểm tra cơ bản đang sử dụng ..

Bạn đã thử các khu vực thử nghiệm mã bằng cách sử dụng Android Mock Framework chưa?


1
không quá nhiều, việc kiểm tra bản chất đó không phải là vấn đề quá lớn khi ghi lại những gì thực sự xảy ra trong khi ứng dụng chạy, thứ tôi thực sự cần là một công cụ lược tả rò rỉ tài nguyên / bộ nhớ
jottos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.