메모리 / 리소스 누수를 찾는 데 가장 적합한 Android 도구 및 방법은 무엇입니까? [닫은]


152

저는 Android 앱을 개발했고 모든 것이 잘 작동하는 것처럼 보이는 전화 앱 개발 시점에 있으며 승리와 함선을 선언하고 싶지만 메모리와 리소스 누수가 있어야한다는 것을 알고 있습니다. 거기에; 그리고 안드로이드에는 16MB의 힙이 있으며 안드로이드 앱에서 쉽게 유출되기 쉽습니다.

나는 주변을 둘러 보았고 지금까지 'hprof'와 'traceview'에 대한 정보 만 파헤칠 수 있었고 어느 ​​쪽도 많은 호평을 얻지 못했습니다.

OS 프로젝트에서 어떤 도구 나 방법을 접했거나 개발하고 공유하려고 했습니까?


3
Р̀СТȢѸ́ФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ의 이름을 사람이 읽을 수있는 이름으로 변경하도록 투표 할 수 있습니까?
JPM

1
질문 제목에서 "Android 도구"라는 단어를 제거하면이 질문을 다시 열어도 될까요? 대답은 확실히 내 메모리 누수 문제를 해결하기 위해 유용하고 여기
K3B

좋습니다. 사용자가 활동간에 지속적으로 전환하고 있습니다. 즉, 20 초 동안 15 개의 활동을 전환했을 수 있습니다. 메모리 부족 오류의 원인이 될 수 있습니까? 수정하려면 어떻게해야합니까? 감사!
Ruchir Baronia

1
질문이 종료 되었기 때문에 답변으로 제공 할 수 없지만 Leak Canary를 살펴 보는 것이 좋습니다 . 앱을 사용하고 활동을 열고 닫은 다음 라이브러리가 작업을 수행하도록하십시오. 누출이 발생한 위치에 대해서도 알려줍니다. 누출이 발생한 후 누출 분석기가 작업을 수행 할 시간을 주면됩니다. 누출 원인을 찾을 때까지 일반적으로 약 2 분 이상 걸립니다. 그 후에 앱 내에서 깔끔하게 보여줄 것입니다. 추가 도구가 필요하지 않습니다!
ubuntudroid

답변:


90

Android 앱을 개발하면서 발견 한 가장 일반적인 오류 중 하나는 'java.lang.OutOfMemoryError : Bitmap Size Exceeds VM Budget'오류입니다. 방향을 변경 한 후 많은 비트 맵을 사용하는 활동에서이 오류가 자주 발견되었습니다. 활동이 파괴되고 다시 생성되고 레이아웃이 비트 맵에 사용할 수있는 VM 메모리를 사용하는 XML에서 "팽창"됩니다.

이전 활동 레이아웃의 비트 맵은 해당 활동에 대한 참조를 교차했기 때문에 가비지 수집기에 의해 제대로 할당 해제되지 않습니다. 많은 실험 끝에이 문제에 대한 아주 좋은 해결책을 찾았습니다.

먼저 XML 레이아웃의 상위 뷰에서 "id"속성을 설정합니다.

<?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"
     >
     ...

그런 다음 Activity의 onDestroy () 메서드에서 unbindDrawables () 메서드를 호출하여 부모 View에 참조를 전달한 다음 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();
    }
}

이 unbindDrawables () 메서드는 뷰 트리를 재귀 적으로 탐색하고 다음을 수행합니다.

  1. 모든 백그라운드 드로어 블에서 콜백을 제거합니다.
  2. 모든 뷰 그룹에서 자식을 제거합니다.

3
일반적인 문제에 대한 좋은 해결책.
While-E

9
AdapterView의 하위 클래스 (ListView, GridView 등)에서는 작동하지 않습니다.
Arjun 2011

@Arjun Yes .. 그것은 AdapterView 하위 클래스에서 작동하지 않습니다. 이를 위해 예외를 처리해야합니다. 나머지는 잘 작동합니다. 그것이 내가 내 코드에서 사용하는 것이고 잘 작동합니다. 도움이 되었기를 바랍니다.
hp.android 2011

@ hp.android "예외에서 이것을 처리"하면 어떻게 생겼는지에 대한 예가 있습니까? 내 이미지 페이지가 PageAdapter
있고이

4
@Jackson은 조건을 변경합니다 : if (view instanceof ViewGroup &&! (view instanceof AdapterView)) 이것은 어댑터에 대해받는 예외를 제거합니다
hp.android


28

주로 미래의 Google 여행자에게 :

불행히도 대부분의 Java 도구는 JVM-Heap 만 분석하기 때문에이 작업에 적합하지 않습니다. 하지만 모든 Android 애플리케이션에는 기본 힙도 있으며, 이는 최대 16MB 제한에 맞아야합니다. 예를 들어 일반적으로 비트 맵 데이터에 사용됩니다. 따라서 많은 드로어 블을 사용하는 경우 JVM-Heap이 약 3MB로 차가워 지더라도 Out Of Memory 오류가 발생할 수 있습니다.


6
Android 3.0 (honeycomb) 드로어 블을 시작하면 힙에 저장됩니다
Gu1234

@Timo 그러면 네이티브 힙에서 누수를 감지하기 위해 무엇을 사용 하시겠습니까?
sydd

1
테스트, 많은 테스트. 문제는 메모리 공유 및 기타 최적화 기술로 인해 앱이 얼마나 많은 메모리를 사용하고 있는지조차 알 수 없다는 것입니다. 일반적인 쉘 명령을 사용하여 메모리 판독 값을 얻을 수 있지만 이는 매우 대략적인 추정치입니다.
Timo Ohr 2011

20

그냥 내 경우에는, 비트 맵 배경 작업 만하는 경우 @ hp.android에서 대답은 잘 작동, 나는이 한 BaseAdapter세트 제공하는 ImageViewA의들 GridView. unbindDrawables()조건이 다음과 같도록 조언 된대로 방법을 수정했습니다 .

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

그러나 문제는 재귀 메서드가 AdapterView. 이 문제를 해결하기 위해 대신 다음을 수행했습니다.

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();
}

의 자식 AdapterView이 여전히 처리되도록-메서드는 지원되지 않는 모든 자식을 제거하려고 시도하지 않습니다.

그러나 ImageViews는 배경이 아닌 비트 맵을 관리 하므로 문제가 해결되지 않습니다 . 따라서 다음을 추가했습니다. 이상적이지는 않지만 작동합니다.

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

전반적으로 unbindDrawables()방법은 다음과 같습니다.

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();
  }
}

그러한 자원을 확보하는 데보다 원칙적인 접근 방식이 있기를 바랍니다.


12

Android의 메모리 관리에 대한 좋은 Google I / O 토크 (2011) 및 메모리 프로파일 링을위한 도구 및 기술에 대한 세부 정보 :
http://www.youtube.com/watch?v=_CruQY55HOk


4
또는 해당 블로그 게시물 : android-developers.blogspot.com/2011/03/…
greg7gkb 2011

1
좋습니다. 사용자가 활동간에 지속적으로 전환하고 있습니다. 즉, 20 초 동안 15 개의 활동을 전환했을 수 있습니다. 메모리 부족 오류의 원인이 될 수 있습니까? 수정하려면 어떻게해야합니까? 감사!'
Ruchir Baronia


1

글쎄요, 그것들은 Android가 사용하는 고유 한 형식과 연결되는 도구입니다. 불만족 할 수있는 것은 사용중인 기본 테스트 코드 프레임 워크입니다.

Android Mock Framework를 사용하여 코드의 모의 테스트 영역을 시도해 보셨습니까?


1
그다지 많지 않습니다. 그 성격을 테스트하는 것은 애플리케이션이 실행되는 동안 실제로 일어나는 일을 기록하는 것만 큼 문제가 아닙니다. 제가 정말로 필요한 것은 리소스 / 메모리 누출 프로파일 링 도구입니다
jottos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.