Android에서 현재 메모리 사용량을 얻는 방법은 무엇입니까?


108

나는 / proc / meminfo를 사용하고 명령 응답을 구문 분석했지만 결과는 다음과 같습니다.

메모리 합계 : 94348 kB 메모리 없음 : 5784 kB

방법. 5MB의 여유 메모리 만 있음을 보여줍니다. 안드로이드 모바일로 가능합니까? 내 모바일에 5-6 개의 애플리케이션 만 설치되어 있고 다른 작업은 실행되지 않습니다. 그러나 여전히이 명령은 사용 가능한 메모리가 거의 없음을 보여줍니다.

누군가 이것을 명확히 할 수 있습니까? 또는 안드로이드에서 메모리 사용량을 얻는 다른 방법이 있습니까?


2
기기 별 또는 앱별 여유 메모리를 확인하려고합니까? 앱당 경우 힙 a-la에서 계산해야합니다 Debug.getNativeHeapFreeSize().
IgorGanapolsky

1
/ proc / meminfo를 사용하여 여유 메모리 (RAM에서)를 계산하려면 MemFree , Buffers , CachedSwapCached 집계를 가져와야 합니다. API 16 이상에서 작동하는 Android에서 제공하는이 목적을위한 API가 있습니다. Meminfo는 이전 API를 대상으로하는 경우 유용합니다.
AB

답변:


174

주의 :이 답변은 장치의 메모리 사용량 / 사용 가능 여부를 측정합니다. 이것은 귀하의 앱에서 사용할 수있는 것이 아닙니다. 앱이 수행하는 작업을 측정하고 수행 할 수 있도록 허용 하려면 Android 개발자의 답변을 사용하십시오 .


Android 문서-ActivityManager.MemoryInfo

  1. parse / proc / meminfo 명령. 여기에서 참조 코드를 찾을 수 있습니다. Android에서 메모리 사용량 가져 오기

  2. 아래 코드를 사용하고 현재 RAM을 얻으십시오.

    MemoryInfo mi = new MemoryInfo();
    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    activityManager.getMemoryInfo(mi);
    double availableMegs = mi.availMem / 0x100000L;
    
    //Percentage can be calculated for API 16+
    double percentAvail = mi.availMem / (double)mi.totalMem * 100.0;

번호 0x100000L에 대한 설명

1024 bytes      == 1 Kibibyte 
1024 Kibibyte   == 1 Mebibyte

1024 * 1024     == 1048576
1048576         == 0x100000

숫자가 바이트에서 메비 바이트로 변환하는 데 사용된다는 것은 분명합니다.

추신 : 총 메모리를 한 번만 계산하면됩니다. 따라서 코드에서 포인트 1을 한 번만 호출 한 다음 그 후에 포인트 2의 코드를 반복적으로 호출 할 수 있습니다.


메모리 용량을 확인하고 싶은데 MemoryInfo 란?
Piraba 2011

PIraba, Android API 클래스. 여기에서 확인하십시오 developer.android.com/reference/android/app/… .
Badal 2012

@SanjayJoshi availMem 변수에 메모리가 바이트 단위로 포함되어 있기 때문입니다. 1024 바이트는 1 킬로바이트와 같고 1024 킬로바이트는 1 메가 바이트와 같습니다. 따라서 1024 * 1024는 1048576과 같음
Rolf ツ

2
위의 두 배로 변환, 다른 percentAvail이 될 것이다 0
blueether

1
@Rolf ツ 미안하지만 1024 바이트는 1 Kibibyte와 같고 1024 Kibibyte는 1 MibiByte입니다. Kilo 및 Mega는 십진수 접두사입니다. 1000 바이트 = 1 킬로바이트. 이것은 또한 대답에서 잘못 설명되었습니다.
JacksOnF1re

88

얻고 자하는 메모리 쿼리의 정의에 따라 다릅니다.


일반적으로 힙 메모리의 상태를 알고 싶습니다. 메모리를 너무 많이 사용하면 OOM이 발생하고 앱이 충돌하기 때문입니다.

이를 위해 다음 값을 확인할 수 있습니다.

final Runtime runtime = Runtime.getRuntime();
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

"usedMemInMB"변수가 "maxHeapSizeInMB"에 가까워 질 availHeapSizeInMB수록 0에 가까울수록 OOM이 가까워집니다. (메모리 조각화로 인해 0에 도달하기 전에 OOM이 발생할 수 있습니다.)

그것은 또한 메모리 사용량의 DDMS 도구가 보여주는 것입니다.


또는 전체 시스템이 사용하는 실제 RAM 사용량 이 있습니다.이를 계산 하려면 허용 된 답변 을 참조하십시오 .


업데이트 : Android O는 앱이 기본 RAM (적어도 메모리 사용량이 큰 주된 이유 인 Bitmaps 저장소의 경우)을 사용하도록 만들기 때문에 힙뿐만 아니라 상황이 변경되었으며 OOM이 줄어들 기 때문입니다. 힙에 더 이상 비트 맵이 포함되어 있지 않습니다. 여기 에서 확인 하십시오 ).하지만 메모리 누수가 의심되는 경우에도 메모리 사용을 주시해야합니다. Android O에서 이전 버전에서 OOM을 유발해야하는 메모리 누수가있는 경우 잡을 수없는 상태에서 충돌이 발생하는 것 같습니다. 메모리 사용량을 확인하는 방법은 다음과 같습니다.

val nativeHeapSize = Debug.getNativeHeapSize()
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize

하지만 그래프를 사용하여 실시간으로 데이터를 보여주는 IDE의 프로파일 러를 사용하는 것이 가장 좋습니다.

따라서 Android O의 좋은 소식은 너무 많은 큰 비트 맵을 저장하는 OOM으로 인해 충돌이 발생하기가 훨씬 더 어렵다는 것입니다. 그러나 나쁜 소식은 런타임 중에 이러한 경우를 포착 할 수 없다고 생각한다는 것입니다.


편집 : Debug.getNativeHeapSize()앱의 총 최대 메모리를 보여주기 때문에 시간이 지남에 따라 변경되는 것 같습니다 . 따라서 이러한 함수는 앱이 얼마나 많이 사용하고 있는지 보여주기 위해 프로파일 러에만 사용됩니다.

실제 총 및 사용 가능한 기본 RAM을 얻으려면 다음을 사용하십시오.

val memoryInfo = ActivityManager.MemoryInfo()
(getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(memoryInfo)
val nativeHeapSize = memoryInfo.totalMem
val nativeHeapFreeSize = memoryInfo.availMem
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize
Log.d("AppLog", "total:${Formatter.formatFileSize(this, nativeHeapSize)} " +
        "free:${Formatter.formatFileSize(this, nativeHeapFreeSize)} " +
        "used:${Formatter.formatFileSize(this, usedMemInBytes)} ($usedMemInPercentage%)")

와. 간단하지만 사실입니다!
Ran

실제 메모리 사용량은 얼마입니까? 이 경우 usedMemInMB는 앱의 실제 메모리 사용량이 아닙니까? 이 코드를 사용하면 사용량이 50mb와 같지만 전화 설정으로 이동하여 메모리 사용량을 보면 앱이 100mb를 표시합니다. 이 차이점이 무엇입니까?
batmaci

1
@batmaci 힙 메모리는 앱의 총 메모리 사용량의 일부일뿐입니다. 일반적으로 웹 페이지, 게임 및 일부 무거운 목적에 사용되는 기본 메모리 사용량도 있습니다. 일반적으로 앱은 기기 RAM에 비해 매우 낮기 때문에 힙 메모리 만 확인해야하며,이 메모리에 도달하면 앱이 충돌합니다 (사용 가능한 RAM이 많더라도).
안드로이드 개발자

OOM을 확인하는 데 매우 유용한 완벽한 코드 스 니펫입니다. 정말 감사합니다.
aolphn

@AlphaOF 감사합니다.하지만 Android O에서는 상황이 바뀌 었습니다. 그곳의 상황에 맞게 답변을 업데이트했습니다.
안드로이드 개발자

29

현재 실행중인 애플리케이션의 메모리 사용량을 계산하는 방법은 다음과 같습니다 .

public static long getUsedMemorySize() {

    long freeSize = 0L;
    long totalSize = 0L;
    long usedSize = -1L;
    try {
        Runtime info = Runtime.getRuntime();
        freeSize = info.freeMemory();
        totalSize = info.totalMemory();
        usedSize = totalSize - freeSize;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return usedSize;

}

4
간단한 접근 방식이지만 설명서에 표시된대로 Runtime 클래스 freeMemory () 메서드는 현재 프로그램 또는 응용 프로그램에 사용 가능한 메모리를 반환합니다. 따라서 사용하는 동안 그것에 유의하십시오.
Aksel Fatih 2013

2
@Peter-예, 질문 한 것과 다른 질문에 답한다는 점에서 "틀 렸습니다". 반면에, 이것은 앱 개발자가 일반적으로 알아야하는 것에 대해 "올바른"것입니다. DEVICE의 전체 메모리 상태가 무엇인지는 거의 중요하지 않습니다. 사용자가 많은 앱을 실행했다면 OS 대부분의 메모리-그렇지 않으면 비효율적입니다. OS는 최근에 사용되지 않은 앱을 언제 종료해야하는지 알기 위해 허용 된 답변이 무엇을 제공하는지 알아야합니다. 그러나 앱 프로그래머는 runtime.maxMemory와 비교하여이 답변 (및 안드로이드 개발자의 유사한 답변)이 무엇을 알려주는지 알아야합니다.
ToolmakerSteve

이 솔루션은 런타임에 의해 앱에 노출 된 메모리에서만 작동합니다. 이것은 OP가 요구하는 전체 시스템 메모리에 대한 통찰력을 제공하지 않습니다.
AB

많은 장치 (예 : Xiaomi) Runtime.freeMemory()에서 0을 Runtime.totalMemory()반환하고 현재 할당 된 메모리 만 반환합니다.
artem

17

다른 방법 (현재 G1에서 25MB 여유 공간 표시) :

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;

안녕 Alex, 도와 주셔서 감사합니다! 질문이 1 개 더 있습니다. 이 코드는 사용 가능한 RAM을 제공합니다. Total RAM도 표시하고 싶습니다. 그것을 얻는 방법?
Badal

@Badal 나는 그것에 대한 Java API를 모른다. / proc / meminfo 구문 분석을 고수하십시오.
yanchenko

12

Linux의 메모리 관리 철학은 "사용 가능한 메모리는 메모리 낭비입니다"입니다.

다음 두 줄은 "Buffers"에 얼마나 많은 메모리가 있고 "Cached"에 얼마나 많은지 보여줄 것이라고 가정합니다. 둘 사이에는 차이가 있지만 (그 차이가 무엇인지 묻지 마십시오.) 둘 다 대략적으로 파일 데이터와 메타 데이터를 캐시하는 데 사용되는 메모리 양에 추가됩니다.

Linux 시스템에서 메모리를 확보하는 데 훨씬 더 유용한 가이드는 free(1)명령입니다. 내 데스크톱에서는 다음과 같은 정보를보고합니다.

$ 무료 -m
             캐시 된 총 사용 된 사용 가능한 공유 버퍼
메모리 : 5980 1055 4924 0 91 374
-/ + 버퍼 / 캐시 : 589 5391
스왑 : 6347 0 6347

+/- 버퍼 / 캐시 : 라인은 마법의 라인이며, 실제로 필요한 프로세스 메모리는 약 589 메가, 91 + 374 메가 바이트라는 의미에서 약 5391 메가의 '사용 가능한'메모리가 있다고보고합니다. 메모리를 다른 곳에서 더 수익성있게 사용할 수 있다면 버퍼 / 캐시 된 메모리의 수를 버릴 수 있습니다.

(내 컴퓨터는 약 3 시간 동안 가동되어 스택 오버플로 외에는 거의 아무것도하지 않았기 때문에 여유 메모리가 너무 많습니다.)

Android가 함께 제공되지 않는 경우 파일을 free(1)사용하여 직접 계산할 수 있습니다 /proc/meminfo. free(1)출력 형식이 마음에 듭니다. :)


1
@Igor, 그러면 cat /proc/meminfo대신 원할 것입니다. 훨씬 더 상세하지만 MemFree. Buffers, 그리고 Cached아마도 가장 중요한 라인 일 것입니다.
sarnold

6

나는 몇 가지 글을 참조합니다.

참고:

이 getMemorySize () 메서드는 전체 및 여유 메모리 크기가있는 MemorySize를 반환합니다.
이 코드를 완벽하게 믿지 않습니다.
이 코드는 LG G3 cat.6 (v5.0.1)에서 테스트 중입니다.

    private MemorySize getMemorySize() {
        final Pattern PATTERN = Pattern.compile("([a-zA-Z]+):\\s*(\\d+)");

        MemorySize result = new MemorySize();
        String line;
        try {
            RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
            while ((line = reader.readLine()) != null) {
                Matcher m = PATTERN.matcher(line);
                if (m.find()) {
                    String name = m.group(1);
                    String size = m.group(2);

                    if (name.equalsIgnoreCase("MemTotal")) {
                        result.total = Long.parseLong(size);
                    } else if (name.equalsIgnoreCase("MemFree") || name.equalsIgnoreCase("Buffers") ||
                            name.equalsIgnoreCase("Cached") || name.equalsIgnoreCase("SwapFree")) {
                        result.free += Long.parseLong(size);
                    }
                }
            }
            reader.close();

            result.total *= 1024;
            result.free *= 1024;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    private static class MemorySize {
        public long total = 0;
        public long free = 0;
    }

Pattern.compile ()은 비용이 많이 들기 때문에 코드를 클래스 멤버로 옮길 수 있습니다.


3

Android 소스 트리를 살펴 보았습니다.

com.android.server.am 내부. ActivityManagerService.java (android.app. ActivityManager에 의해 노출 된 내부 서비스 ).

public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
    final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
    final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
    outInfo.availMem = Process.getFreeMemory();
    outInfo.totalMem = Process.getTotalMemory();
    outInfo.threshold = homeAppMem;
    outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
    outInfo.hiddenAppThreshold = hiddenAppMem;
    outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
            ProcessList.SERVICE_ADJ);
    outInfo.visibleAppThreshold = mProcessList.getMemLevel(
            ProcessList.VISIBLE_APP_ADJ);
    outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
            ProcessList.FOREGROUND_APP_ADJ);
}

android.os 내부. Process.java

/** @hide */
public static final native long getFreeMemory();

/** @hide */
public static final native long getTotalMemory();

android_util_Process.cpp 에서 JNI 메소드를 호출합니다 .

결론

MemoryInfo.availMem = MemFree + / proc / meminfo에 캐시 됨.

노트

총 메모리는 API 레벨 16에 추가됩니다.


1

Android SDK 자체의 일부인 DDMS 도구를 사용할 수도 있습니다. 자바 코드와 네이티브 C / C ++ 코드의 메모리 할당을 얻는데도 도움이됩니다.


0
public static boolean isAppInLowMemory(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);

    return memoryInfo.lowMemory;
}

0
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

이상한 코드입니다. MaxMemory-(totalMemory-freeMemory)를 반환합니다. freeMemory가 0이면 코드는 MaxMemory-totalMemory를 반환하므로 0 이상이 될 수 있습니다. freeMemory가 사용되지 않는 이유는 무엇입니까?


0

앱의 메모리 사용량을 보는 또 다른 방법은 다음과 같습니다.

adb shell dumpsys meminfo <com.package.name> -d

샘플 출력 :

Applications Memory Usage (kB):
Uptime: 2896577 Realtime: 2896577

** MEMINFO in pid 2094 [com.package.name] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     3472     3444        0        0     5348     4605      102
  Dalvik Heap     2349     2188        0        0     4640     4486      154
 Dalvik Other     1560     1392        0        0
        Stack      772      772        0        0
    Other dev        4        0        4        0
     .so mmap     2749     1040     1220        0
    .jar mmap        1        0        0        0
    .apk mmap      218        0       32        0
    .ttf mmap       38        0        4        0
    .dex mmap     3161       80     2564        0
   Other mmap        9        4        0        0
      Unknown       76       76        0        0
        TOTAL    14409     8996     3824        0     9988     9091      256

 Objects
               Views:       30         ViewRootImpl:        2
         AppContexts:        4           Activities:        2
              Assets:        2        AssetManagers:        2
       Local Binders:       17        Proxy Binders:       21
    Death Recipients:        7
     OpenSSL Sockets:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

전체 메모리 사용량 :

adb shell dumpsys meminfo

https://developer.android.com/studio/command-line/dumpsys#meminfo

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.