Android에서 애플리케이션 힙 크기 감지


답변:


453

"응용 프로그램 힙 크기 사용 가능"이라는 문구를 생각하는 두 가지 방법이 있습니다.

  1. 하드 오류가 발생하기 전에 앱에서 얼마나 많은 힙을 사용할 수 있습니까? 과

  2. Android OS 버전과 사용자 기기 하드웨어의 제약 조건을 감안할 때 내 앱에서 얼마나 많은 힙을 사용해야 합니까?

위의 각각을 결정하는 다른 방법이 있습니다.

위 항목 1의 경우 : maxMemory()

onCreate()다음과 같이 호출 될 수 있습니다 (예 : 기본 활동의 메소드에서).

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

이 방법은 앱 에서 사용할 수있는 총 총 바이트 수를 알려줍니다 .

위의 항목 2의 경우 : getMemoryClass()

다음과 같이 호출 할 수 있습니다.

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

이 방법은 현재 장치의 제한과 무례하게 반복 / 사이클에 강제로 적용되지 않고 다른 앱의 실행 권한을 올바르게 존중하려면 앱에서 사용해야 하는 대략 몇 메가 바이트 의 힙을 알려줍니다 귀하의 코끼리 앱이 안드로이드 자쿠지에서 목욕을하는 동안 메모리에서 플러시.onStop()onResume()

이 구별은 내가 아는 한 명확하게 문서화되어 있지는 않지만 5 가지 Android 장치 (아래 참조) 에서이 가설을 테스트했으며 이것이 올바른 해석임을 스스로 확인했습니다.

Android의 재고 버전의 maxMemory()경우 일반적으로 표시된 것과 동일한 수의 메가 바이트를 반환합니다 getMemoryClass()(즉, 후자의 값의 약 백만 배).

두 가지 방법을 분기 할 수있는 유일한 상황은 CyanogenMod와 같은 Android 버전을 실행하는 루팅 된 장치에서 사용자가 각 앱에 대해 얼마나 큰 힙 크기를 허용할지 선택할 수 있습니다. 예를 들어 CM에서이 옵션은 "CyanogenMod settings"/ "Performance"/ "VM heap size"아래에 나타납니다.

참고 : 장치에 정상보다 작은 값을 선택하면이 값을 수동으로 설정하여 시스템을 관리 할 수 ​​있다는 점에 유의하십시오.

여기에서 반환 된 값을 보여주는 내 테스트 결과입니다 maxMemory()getMemoryClass()각각에 대해 서로 다른 두 가지 (수동 설정) 힙 값을 사용하여 사이 애 노젠 모드를 실행하는 네 가지 장치에는 :

  • G1 :
    • VM 힙 크기가 16MB로 설정된 경우 :
      • 최대 메모리 : 16777216
      • getMemoryClass : 16
    • VM 힙 크기가 24MB로 설정된 경우 :
      • 최대 메모리 : 25165824
      • getMemoryClass : 16
  • 모토 드로이드 :
    • VM 힙 크기가 24MB로 설정된 경우 :
      • 최대 메모리 : 25165824
      • getMemoryClass : 24
    • VM 힙 크기가 16MB로 설정된 경우 :
      • 최대 메모리 : 16777216
      • getMemoryClass : 24
  • Nexus One :
    • VM 힙 크기가 32MB로 설정된 경우 :
      • 최대 메모리 : 33554432
      • getMemoryClass : 32
    • VM 힙 크기가 24MB로 설정된 경우 :
      • 최대 메모리 : 25165824
      • getMemoryClass : 32
  • Viewsonic GTab :
    • VM 힙 크기가 32로 설정된 경우 :
      • 최대 메모리 : 33554432
      • getMemoryClass : 32
    • VM 힙 크기가 64로 설정된 경우 :
      • 최대 메모리 : 67108864
      • getMemoryClass : 32

위의 것 외에도 Ice Cream Sandwich를 실행하는 Novo7 Paladin 태블릿에서 테스트했습니다. 이것은 전체 OS를 대체하지 않는 간단한 프로세스를 통해 태블릿을 근절했으며 특히 힙 크기를 수동으로 조정할 수있는 인터페이스를 제공하지 않는다는 점을 제외하고는 기본적으로 ICS의 기본 버전이었습니다.

해당 장치의 결과는 다음과 같습니다.

  • 노보 7
    • 최대 메모리 : 62914560
    • getMemoryClass : 60

또한 (아래 의견에서 Kishore 당) :

  • HTC 하나 X
    • 최대 메모리 : 67108864
    • getMemoryClass : 64

그리고 (akauppi의 의견에 따라) :

  • 삼성 갤럭시 코어 플러스
    • maxMemory : (의견에 명시되지 않음)
    • getMemoryClass : 48
    • largeMemoryClass : 128

cmcromance의 의견 :

  • Galaxy S3 (Jelly Bean) 대형 힙
    • 최대 메모리 : 268435456
    • getMemoryClass : 64

그리고 (텐센트의 의견 당) :

  • LG Nexus 5 (4.4.3) 정상
    • maxMemory : 201326592
    • getMemoryClass : 192
  • LG Nexus 5 (4.4.3) 대형 힙
    • 최대 메모리 : 536870912
    • getMemoryClass : 192
  • Galaxy Nexus (4.3) 일반
    • 최대 메모리 : 100663296
    • getMemoryClass : 96
  • Galaxy Nexus (4.3) 대형 힙
    • 최대 메모리 : 268435456
    • getMemoryClass : 96
  • Galaxy S4 Play Store Edition (4.4.2) 일반
    • maxMemory : 201326592
    • getMemoryClass : 192
  • Galaxy S4 Play Store Edition (4.4.2) 대형 힙
    • 최대 메모리 : 536870912
    • getMemoryClass : 192

다른 장치들

  • 화웨이 Nexus 6P (6.0.1) 정상
    • maxMemory : 201326592
    • getMemoryClass : 192

Honeycomb부터 사용할 수있는 특수 android : largeHeap = "true"매니페스트 옵션을 사용하여이 두 가지 방법을 테스트하지는 않았지만 cmcromance 및 tencent 덕분에 위에보고 된대로 일부 샘플 bigHeap 값이 있습니다.

기대 (위의 largeHeap 번호에 의해 지원 될 것으로 보인다)이 옵션은 뿌리 OS를 통해 수동으로 힙을 설정 유사한 효과가 것이 될 것 - 즉, 그것의 값 올릴 것이다 maxMemory()떠나있는 동안 getMemoryClass()혼자. 또 다른 메소드 인 getLargeMemoryClass ()가 있는데,이 메소드는 largeHeap 설정을 사용하여 앱에 허용되는 메모리 양을 나타냅니다. getLargeMemoryClass ()에 대한 설명서는 "대부분의 응용 프로그램은이 양의 메모리가 필요하지 않으며 대신 getMemoryClass () 한계를 유지해야합니다."라고 말합니다.

내가 올바르게 추측했다면, 그 옵션을 사용하면 루팅 된 OS를 통해 힙을 올린 사용자가 사용할 수있는 공간을 사용하는 것과 동일한 이점 (및 위험)이 있습니다 (즉, 앱이 추가 메모리를 사용하는 경우, 아마도 사용자가 동시에 실행하는 다른 앱과 잘 어울리지 않을 것입니다).

메모리 클래스는 8MB의 배수 일 필요는 없습니다.

위에서 알 수 있듯이 getMemoryClass()결과는 주어진 장치 / OS 구성에 대해 변경되지 않고 maxMemory () 값은 사용자가 힙을 다르게 설정하면 변경됩니다.

내 실제 경험은 G1 (메모리 클래스 16)에서 수동으로 힙 크기로 24MB를 선택하면 메모리 사용량이 20MB로 표류 할 때도 오류없이 실행할 수 있다는 것입니다 (아마도 나는 이것을 시도하지 않았지만 24MB까지 올라갑니다.) 그러나 다른 비슷한 대형 앱은 내 앱의 돼지의 결과로 메모리에서 플러시 될 수 있습니다. 반대로, 이러한 높은 유지 관리 앱을 사용자가 포 그라운드로 가져 오면 앱이 메모리에서 플러시 될 수 있습니다.

따라서로 지정된 메모리 양을 넘을 수 없습니다 maxMemory(). 그리고, 당신은해야 시도 로 지정된 한도 내에서 머물 getMemoryClass(). 다른 방법으로 모두 실패 할 경우 메모리를 보존하는 방식으로 해당 장치의 기능을 제한하는 것이 좋습니다.

마지막으로에 지정된 메가 바이트를 넘길 계획이라면 getMemoryClass()앱 상태를 저장하고 복원하는 데 오랜 시간과 노력을 기울이는 것이 좋습니다. 따라서 onStop()/ onResume()사이클이 발생할 경우 사용자 경험이 사실상 중단되지 않습니다 .

필자의 경우 성능상의 이유로 앱을 2.2 이상을 실행하는 기기로 제한하고 있으며 이는 내 앱을 실행하는 거의 모든 기기의 메모리 클래스가 24 이상임을 의미합니다. 따라서 최대 20MB의 힙을 차지하도록 설계하고 사용자가 동시에 실행할 수있는 다른 앱과 함께 내 앱이 잘 작동한다고 확신합니다.

그러나 2.2 이상의 버전의 Android를 이전 기기 (예 : G1)에로드 한 루팅 된 사용자는 항상 있습니다. 이러한 구성이 발생하면 이상적으로 maxMemory()는 16MB보다 훨씬 더 많이 갈 수 있다고 말 하더라도 메모리 사용 을 줄일 getMemoryClass()필요 있습니다. 그리고 예산 내에서 앱이 안정적으로 작동하는지 확실하게 보장 할 수 없다면 최소한 onStop()/ onResume()완벽하게 작동 하는지 확인하십시오 .

getMemoryClass()위의 Diane Hackborn (hackbod)에서 알 수 있듯이 API 레벨 5 (Android 2.0)로만 다시 사용할 수 있으므로 이전 버전의 OS를 실행하는 모든 기기의 물리적 하드웨어가 설계되었다고 가정 할 수 있습니다. 16MB 이하의 힙 공간을 차지하는 앱을 최적으로 지원합니다.

이와는 대조적으로 maxMemory(), 문서에 따르면, API 레벨 1에있는 모든 방법을 다시 볼 수 있습니다 maxMemory()2.0 이전의 버전은 아마 16 메가 바이트 값을 반환,하지만 난 것이다 어떻게 내 (더 이상) 사이 애 노젠 모드 버전 사용자에 해당 참조 12MB만큼 낮은 힙 값을 선택할 수 있으므로 힙 제한이 낮아질 수 있으므로 maxMemory()2.0 이전의 OS 버전에서도 값 을 계속 테스트하는 것이 좋습니다 . maxMemory()허용되는 것보다 많은 표시가 필요한 경우이 값이 16MB보다 더 낮게 설정 될 가능성이 낮은 경우에는 실행을 거부해야 할 수도 있습니다 .


2
@Carl Hello Carl, 멋진 게시물 감사합니다. 그리고 JellyBean과 함께 Galaxy S3에서 android : largeHeap = "true"옵션을 테스트했습니다. 결과는 다음과 같습니다. [maxMemory : 256.0MB, memoryClass : 64MB] (maxheap 옵션이없는 maxMemory는 64MB)
cmcromance

1
@Carl Haha 대단한 영광입니다! :)
cmcromance

1
HTC One X의 경우 : maxMemory : 67108864 memoryClass : 64
Kishore

1
LG Nexus 5 (4.4.3) (일반) : maxMemory : 201326592, memoryClass : 192 | LG Nexus 5 (4.4.3) (대용량 힙) : maxMemory : 536870912, memoryClass : 192
ian.shaun.thomas

1
매우 아름답게 기록되어 있습니다. 이것을 안드로이드에 제공하십시오. 적절한 Android 문서를 찾을 수 없습니다
Jimit Patel

20

공식 API 는 다음과 같습니다.

이것은 더 큰 메모리 장치가 나타나는 2.0에서 도입되었습니다. 이전 버전의 OS를 실행하는 장치가 원래 메모리 클래스 (16)를 사용하고 있다고 가정 할 수 있습니다.


13

Debug.getNativeHeapSize()트릭을 할 것 같아요. 1.0 이후로 존재했습니다.

Debug클래스에는 할당 및 기타 성능 문제를 추적하기위한 많은 훌륭한 방법이 있습니다. 또한 메모리 부족 상황을 감지해야하는 경우를 확인하십시오 Activity.onLowMemory().


고마워 닐 디버깅을 끈 상태에서 응용 프로그램을 실행할 때 작동합니까?
hpique

2
나는 이것에 익숙하지 않지만 기본 힙이 질문이 참조하는 앱 (Dalvik) 힙과 동일하다고 생각하지 않습니다. 기본 힙은 비트 맵 데이터에 대한 백업을 제공하며, 비트 맵 데이터는 기본 코드로 할당되며 앱 힙은 Java 애플리케이션 데이터를 보유합니다. 네이티브 힙이 앱 힙 제한에 대해 계산되고 3.0 이후에 실제로 앱 힙에서 할당이 발생한다는 것을 알고 싶습니다. 다이앤 Hackborn (hackbod) 여기이 주제에 대한 게시물 : stackoverflow.com/questions/1945142/bitmaps-in-android 그러나 심지어 3.0은 또한 응용 프로그램 힙에 비 "기본"데이터가있다.
Carl

1
최근의 일부 Android 업데이트 (KitKat 4.4) 이후 비트 맵은 JVM 힙에 있습니다.
akauppi

13

방법은 다음과 같습니다.

앱이 사용할 수있는 최대 힙 크기 얻기

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

앱에서 현재 사용중인 힙의 양 얻기

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

앱이 사용할 수있는 힙의 양 (가용 메모리) 가져 오기 :

long availableMemory=maxMemory-usedMemory;

그리고 각각을 멋지게 형식화하려면 다음을 사용할 수 있습니다.

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 

5

그러면 최대 힙 크기 (바이트)가 반환됩니다.

Runtime.getRuntime().maxMemory()

ActivityManager.getMemoryClass ()를 사용하고 있었지만 CyanogenMod 7 (다른 곳에서는 테스트하지 않았습니다)에서 사용자가 힙 크기를 수동으로 설정하면 잘못된 값을 반환합니다.


에 대한 의사록 getMemoryClass은 숫자가 사용 가능한 VM의 힙 크기와 같지 않을 수 있음을 의미하는 것으로 보이며 의사에 대한 문서 getNativeHeapSize는 ... taciturn이므로 실제로 Runtime.getRuntime().maxMemory()가장 좋은 대답 이라고 생각 합니다.
BoD December

3

일부 작업은 Java 힙 공간 관리자보다 빠릅니다. 일정 시간 동안 작업지연 시키면 메모리 공간을 확보 할 수 있습니다. 이 방법을 사용하여 힙 크기 오류를 피할 수 있습니다.

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {

    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {

    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    waitForGarbageCollector(
      callback);
  } else {

    // Memory resources are availavle, go to next operation:

    callback.run();
  }
}

잘 테스트했습니다. availableMemoryPercentage와 MIN_AVAILABLE_MEMORY_PERCENTAGE의 두 가지를 자세히 설명 할 수 있습니까? 일부 설명?
Noor Hossain

1
AvailableMemoryPercentage공식에 따르면 : 현재 사용 가능한 장치의 메모리 양. MIN_AVAILABLE_MEMORY_PERCENTAGE가비지 콜렉터가 작업을 수행하기를 기다리는 임계 값 인 사용자 정의 매개 변수입니다.
Zon

1

ASUS Nexus 7 (2013) 32Gig : getMemoryClass () = 192 maxMemory () = 201326592

Nexus 7에서 게임 프로토 타이핑하는 실수를 저지른 다음 아내의 일반 4.04 태블릿 (메모리 클래스 48, 최대 메모리 50331648)에서 거의 즉시 메모리 부족을 발견했습니다.

메모리 클래스가 부족하다고 판단되면 더 적은 리소스를로드하도록 프로젝트를 재구성해야합니다.
Java에서 현재 힙 크기를 보는 방법이 있습니까? (디버깅 할 때 logCat에서 명확하게 볼 수 있지만 currentheap> (maxmemory / 2) 고품질 비트 맵을 언로드하는 경우와 같이 코드에서 적응시키는 방법을 원합니다.


Nexus7-2013에서 getLargeMemoryClass () = 512입니다.
akauppi

0

프로그래밍 방식으로 또는 개발 및 디버깅 중입니까? 후자의 경우 Eclipse의 DDMS 관점에서 해당 정보를 볼 수 있습니다. 에뮬레이터 (연결된 실제 전화 일 수도 있음)가 실행 중이면 왼쪽의 창에 활성 프로세스가 나열됩니다. 선택할 수 있으며 힙 할당을 추적하는 옵션이 있습니다.


프로그래밍 방식으로 의미합니다. 질문을 명확히했다. 감사.
hpique

1
그런 다음 Android 플랫폼 프로그래머 중 한 명이이 게시물을 살펴 보는 것이 좋습니다. stackoverflow.com/questions/2298208/…
Steve Haley

0
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

값은 b

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

값은 MB입니다


어떤 유형의 rt? 어디에 선언되어 있습니까?
FindOut_Quran
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.