¿Cómo obtener el uso actual de la memoria en Android?

108

He usado / proc / meminfo y he analizado la respuesta de comando, sin embargo, el resultado muestra que:

MemTotal: 94348 kB MemFree: 5784 kB

medio. muestra que solo hay 5 MB de memoria libre. ¿Es posible con un móvil Android? Solo hay 5-6 aplicaciones instaladas en mi móvil y no se está ejecutando ninguna otra tarea. pero aún así este comando muestra que hay muy poca memoria libre.

¿Alguien puede aclarar esto? ¿O hay alguna otra forma de obtener el uso de la memoria en Android?

Badal
fuente
2
¿Estás intentando ver memoria libre por dispositivo o por aplicación? Si es por aplicación, entonces debe calcularse en el montón a-la Debug.getNativeHeapFreeSize().
IgorGanapolsky
1
Para el cálculo de memoria libre (en la RAM) utilizando / proc / meminfo usted tiene que conseguir el agregado de MemFree , tampones , caché y SwapCached . Hay una API para este propósito proporcionada por Android que funciona en API 16 y en salas. Meminfo es útil si se dirige a API más antiguas.
AB

Respuestas:

174

PRECAUCIÓN: Esta respuesta mide el uso de memoria / disponible del DISPOSITIVO. Esto NO es lo que está disponible para su aplicación. Para medir lo que está haciendo su APLICACIÓN, y está PERMITIDO, use la respuesta del desarrollador de Android .


Documentos de Android: ActivityManager.MemoryInfo

  1. comando parse / proc / meminfo. Puede encontrar el código de referencia aquí: Obtener uso de memoria en Android

  2. use el siguiente código y obtenga la RAM actual:

    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;

Explicación del número 0x100000L

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

1024 * 1024     == 1048576
1048576         == 0x100000

Es bastante obvio que el número se usa para convertir de bytes a mebibyte

PD: necesitamos calcular la memoria total solo una vez. así que llame al punto 1 solo una vez en su código y luego, puede llamar al código del punto 2 repetidamente.

Badal
fuente
Quiero comprobar el tamaño de la memoria. ¿Qué es MemoryInfo?
Piraba
PIraba, su clase de API de Android. Compruébalo aquí developer.android.com/reference/android/app/… .
Badal
@SanjayJoshi Eso es porque la variable availMem contiene la memoria en bytes. 1024 bytes equivalen a 1 kilobyte y 1024 kilobytes equivalen a 1 megabyte. Entonces 1024 * 1024 es igual a 1048576
Rolf ツ
2
Convierta al doble por encima, de lo contrario, el porcentaje de disponibilidad será 0
blueether
1
@Rolf ツ lo siento, pero 1024 bytes equivalen a un Kibibyte y 1024 Kibibyte son un MibiByte. Kilo y Mega son prefijos decimales. 1000 bytes = 1 kilobyte. Esto también está mal explicado en la respuesta.
JacksOnF1re
88

Depende de su definición de la consulta de memoria que desee obtener.


Por lo general, le gustaría saber el estado de la memoria del montón, ya que si usa demasiada memoria, obtiene OOM y bloquea la aplicación.

Para ello, puede comprobar los siguientes valores:

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

Cuanto más se acerca la variable "usedMemInMB" a "maxHeapSizeInMB", cuanto más availHeapSizeInMBse acerca a cero, más se acerca a OOM. (Debido a la fragmentación de la memoria, es posible que obtenga OOM ANTES de que llegue a cero).

Eso es también lo que muestra la herramienta DDMS de uso de memoria.


Alternativamente, existe el uso real de RAM, que es la cantidad que usa todo el sistema; consulte la respuesta aceptada para calcular eso.


Actualización: dado que Android O hace que su aplicación también use la RAM nativa (al menos para el almacenamiento de Bitmaps, que suele ser la razón principal del gran uso de memoria), y no solo el montón, las cosas han cambiado y obtiene menos OOM (porque el heap ya no contiene mapas de bits, verifique aquí ), pero aún debe estar atento al uso de la memoria si sospecha que tiene pérdidas de memoria. En Android O, si tiene pérdidas de memoria que deberían haber causado OOM en versiones anteriores, parece que simplemente fallará sin que pueda detectarlo. A continuación, le indicamos cómo verificar el uso de la memoria:

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

Pero creo que podría ser mejor usar el generador de perfiles del IDE, que muestra los datos en tiempo real, usando un gráfico.

Entonces, la buena noticia en Android O es que es mucho más difícil tener bloqueos debido a que OOM almacena demasiados mapas de bits grandes, pero la mala noticia es que no creo que sea posible detectar un caso así durante el tiempo de ejecución.


EDITAR: parece Debug.getNativeHeapSize() cambia con el tiempo, ya que le muestra la memoria máxima total para su aplicación. Entonces, esas funciones se usan solo para el generador de perfiles, para mostrar cuánto está usando su aplicación.

Si desea obtener la RAM nativa total y disponible real, use esto:

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%)")
desarrollador de Android
fuente
Guau. ¡Tan simple, pero tan cierto!
ejecutó el
¿Cuál es el uso real de la memoria? Entonces, usedMemInMB en este caso ¿no es el uso real de la memoria de la aplicación? Cuando uso este código, me muestra que el uso es como 50mb, pero cuando voy a la configuración del teléfono y veo el uso de la memoria allí, mi aplicación muestra 100mb. ¿Por qué es esta diferencia?
batmaci
1
La memoria de pila de @batmaci es solo una parte del uso total de memoria de la aplicación. También existe el uso de memoria nativa, que generalmente se usa para páginas web, juegos y algunos propósitos pesados. Por lo general, las aplicaciones necesitan buscar solo en la memoria del montón, porque es bastante baja en comparación con la RAM del dispositivo, y si la alcanzan, la aplicación se bloqueará (incluso si hay mucha RAM libre).
desarrollador de Android
Es un fragmento de código perfecto, muy útil para verificar OOM, muchas gracias.
aolphn
@AlphaOF Gracias, pero las cosas han cambiado en Android O. Actualicé la respuesta para que coincida con la situación allí.
desarrollador de Android
29

A continuación, se muestra una forma de calcular el uso de memoria de la aplicación que se está ejecutando actualmente :

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;

}
Sharmilee
fuente
4
Es un enfoque simple, pero como se indicó en la documentación, el método freeMemory () de la clase Runtime devuelve la memoria disponible para el programa o aplicación actual. Así que tenga en cuenta eso mientras usa.
Aksel Fatih
2
@Peter - Sí, está "mal" porque responde una pregunta diferente a la que se hizo. Por otro lado, esto es "correcto" para lo que un desarrollador de aplicaciones normalmente necesita saber: rara vez importa cuál es el estado general de la memoria en el DISPOSITIVO; si el usuario ha ejecutado muchas aplicaciones, el sistema operativo debería utilizar la mayoría de las su memoria; de lo contrario, está siendo ineficaz. El sistema operativo necesita saber cuál es la respuesta aceptada para saber cuándo empezar a eliminar aplicaciones que no se han utilizado recientemente. Pero un programador de aplicaciones necesita saber qué le dice ESTA respuesta (y la respuesta similar del desarrollador de Android), frente a runtime.maxMemory.
ToolmakerSteve
Esta solución simplemente funciona en la memoria expuesta a la aplicación por Runtime. Esto no brinda información sobre la memoria del sistema completo como lo requiere OP.
AB
En muchos dispositivos (por ejemplo, Xiaomi) Runtime.freeMemory()devuelve 0 y Runtime.totalMemory()devuelve solo la memoria asignada actualmente.
Artem
17

Otra forma (actualmente muestra 25 MB gratis en mi G1):

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
Yanchenko
fuente
Hola Alex, ¡muchas gracias por tu ayuda! 1 pregunta más. Este código me da RAM disponible. También quiero mostrar la RAM total. ¿Cómo conseguir eso?
Badal
@Badal No conozco una API de Java para eso. Cíñete a analizar / proc / meminfo.
Yanchenko
12

La filosofía de administración de memoria de Linux es "La memoria libre es memoria desperdiciada".

Supongo que las siguientes dos líneas mostrarán cuánta memoria hay en "Búferes" y cuánta está "en caché". Si bien existe una diferencia entre los dos (no pregunte cuál es esa diferencia :), ambos se suman aproximadamente a la cantidad de memoria utilizada para almacenar en caché los datos y metadatos de archivos.

Una guía mucho más útil para liberar memoria en un sistema Linux es el free(1)comando; en mi escritorio, informa información como esta:

$ gratis -m
             total de búferes compartidos libres usados ​​almacenados en caché
Mem: 5980 1055 4924 0 91 374
- / + búferes / caché: 589 5391
Permuta: 6347 0 6347

La línea +/- buffers / cache: es la línea mágica, informa que realmente tengo alrededor de 589 megas de memoria de proceso activamente requerida y alrededor de 5391 megas de memoria 'libre', en el sentido de que los 91 + 374 megabytes de búferes / memoria caché se pueden desechar si la memoria se puede utilizar de manera más rentable en otro lugar.

(Mi máquina ha estado funcionando durante aproximadamente tres horas, sin hacer casi nada más que stackoverflow, razón por la cual tengo tanta memoria libre).

Si Android no viene incluido free(1), puedes hacer los cálculos tú mismo con el /proc/meminfoarchivo; Simplemente me gusta el free(1)formato de salida. :)

sarnold
fuente
1
@Igor, entonces querrás cat /proc/meminfohacerlo. Es mucho más detallado, pero MemFree. Buffers, y Cachedprobablemente sean las líneas más importantes.
sarnold
6

Menciono pocos escritos.

referencia:

Este método getMemorySize () devuelve MemorySize que tiene un tamaño de memoria total y libre.
No creo este código perfectamente.
Este código se está probando en 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;
    }

Sé que Pattern.compile () tiene un costo elevado, por lo que puede mover su código al miembro de la clase.

Hogun
fuente
3

Miré el árbol de fuentes de Android.

Dentro de com.android.server.am. ActivityManagerService.java (servicio interno expuesto por 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);
}

Dentro de android.os. Process.java

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

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

Llama al método JNI desde android_util_Process.cpp

Conclusión

MemoryInfo.availMem = MemFree + Caché en / proc / meminfo.

Notas

La memoria total se agrega en el nivel de API 16.

ragazenta
fuente
1

También puede utilizar la herramienta DDMS, que forma parte del SDK de Android. también ayuda a obtener asignaciones de memoria del código Java y del código nativo C / C ++.

vsmph
fuente
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;
}
iMobaio
fuente
0
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

Es un código extraño. Devuelve MaxMemory - (totalMemory - freeMemory). Si freeMemory es igual a 0, entonces el código devolverá MaxMemory - totalMemory, por lo que puede ser mayor o igual a 0. ¿Por qué no se usa freeMemory?

Andrey
fuente
0

Aquí hay otra forma de ver el uso de memoria de su aplicación:

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

Salida de muestra:

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

Para el uso general de la memoria:

adb shell dumpsys meminfo

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

usuario1506104
fuente