Come ottenere l'utilizzo della memoria corrente in Android?


108

Ho usato / proc / meminfo e analizzato la risposta al comando. Comunque il risultato mostra che:

MemTotal: 94348 kB MemFree: 5784 kB

si intende. mostra che ci sono solo 5 MB di memoria libera. È possibile con dispositivi mobili Android? Sul mio cellulare sono installate solo 5-6 applicazioni e nessun'altra attività è in esecuzione. ma ancora questo comando mostra che c'è poca memoria libera.

Qualcuno può chiarire questo? o c'è un altro modo per ottenere l'utilizzo della memoria in Android?


2
Stai cercando di vedere la memoria libera per dispositivo o per app? Se per app, deve essere calcolato sull'heap a-la Debug.getNativeHeapFreeSize().
IgorGanapolsky

1
Per calcolare la memoria libera (in RAM) tramite / proc / meminfo è necessario ottenere l'aggregato di MemFree , buffer , cache e SwapCached . C'è un'API per questo scopo fornita da Android che funziona sull'API 16 e sui reparti. Meminfo è utile se stai prendendo di mira API meno recenti.
AB

Risposte:


174

ATTENZIONE: questa risposta misura l'utilizzo della memoria / disponibile del DISPOSITIVO. Questo NON è ciò che è disponibile per la tua app. Per misurare cosa sta facendo la tua APP ed è CONSENTITO di fare, usa la risposta dello sviluppatore Android .


Documenti Android: ActivityManager.MemoryInfo

  1. comando parse / proc / meminfo. Puoi trovare il codice di riferimento qui: Ottieni utilizzo della memoria in Android

  2. usa il codice sottostante e ottieni la RAM corrente:

    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;
    

Spiegazione del numero 0x100000L

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

1024 * 1024     == 1048576
1048576         == 0x100000

È abbastanza ovvio che il numero viene utilizzato per convertire da byte a mebibyte

PS: dobbiamo calcolare la memoria totale solo una volta. quindi chiama il punto 1 solo una volta nel tuo codice e poi dopo, puoi chiamare il codice del punto 2 ripetutamente.


Voglio controllare la dimensione della memoria Cos'è MemoryInfo?
Piraba

PIraba, la sua classe API Android. Controllalo qui developer.android.com/reference/android/app/… .
Badal

@SanjayJoshi Questo perché la variabile availMem contiene la memoria in byte. 1024 byte equivalgono a 1 KiloByte e 1024 kilobyte equivalgono a 1 MegaByte. Quindi 1024 * 1024 è uguale a 1048576
Rolf ツ

2
Converti per raddoppiare sopra, altrimenti percentAvail sarà 0
blueether

1
@Rolf ツ scusa ma 1024 byte equivalgono a un Kibibyte e 1024 Kibibyte sono un MibiByte. Kilo e Mega sono prefissi decimali. 1000 byte = 1 Kilobyte. Anche questo è sbagliato spiegato nella risposta.
JacksOnF1re

88

Dipende dalla tua definizione di quale query di memoria desideri ottenere.


Di solito, ti piacerebbe conoscere lo stato della memoria heap, poiché se utilizza troppa memoria, ottieni OOM e l'app si blocca.

Per questo, puoi controllare i seguenti valori:

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

Più la variabile "usedMemInMB" si avvicina a "maxHeapSizeInMB", più ci availHeapSizeInMBsi avvicina allo zero, più si avvicina l'OOM. (A causa della frammentazione della memoria, potresti ottenere OOM PRIMA che raggiunga lo zero.)

Questo è anche ciò che mostra lo strumento DDMS di utilizzo della memoria.


In alternativa, c'è il reale utilizzo della RAM, che è quanto utilizza l'intero sistema - vedi la risposta accettata per calcolarlo.


Aggiornamento: poiché Android O fa in modo che la tua app utilizzi anche la RAM nativa (almeno per l'archiviazione Bitmap, che di solito è il motivo principale per un enorme utilizzo della memoria), e non solo l'heap, le cose sono cambiate e ottieni meno OOM (perché il heap non contiene più bitmap, controlla qui ), ma dovresti comunque tenere d'occhio l'uso della memoria se sospetti di avere perdite di memoria. Su Android O, se hai perdite di memoria che avrebbero dovuto causare OOM su versioni precedenti, sembra che si bloccherà senza che tu sia in grado di rilevarlo. Ecco come verificare l'utilizzo della memoria:

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

Ma credo che potrebbe essere meglio usare il profiler dell'IDE, che mostra i dati in tempo reale, utilizzando un grafico.

Quindi la buona notizia su Android O è che è molto più difficile ottenere arresti anomali a causa di OOM di memorizzare troppe bitmap di grandi dimensioni, ma la cattiva notizia è che non penso sia possibile rilevare un caso del genere durante il runtime.


MODIFICA: sembra che Debug.getNativeHeapSize()cambi nel tempo, in quanto ti mostra la memoria massima totale per la tua app. Quindi queste funzioni vengono utilizzate solo per il profiler, per mostrare quanto sta utilizzando la tua app.

Se vuoi ottenere la RAM nativa totale e disponibile reale, usa questo:

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%)")

Wow. Così semplice, ma così vero!
Ha corso il

qual è il reale utilizzo della memoria? così usatoMemInMB in questo caso non è l'utilizzo reale della memoria dell'app? Quando uso questo codice, mi mostra che l'utilizzo è come 50 MB, ma quando vado alle impostazioni del telefono e vedo l'utilizzo della memoria lì, la mia app mostra 100 MB. perché è questa differenza?
batmaci

1
@batmaci Heap memory è solo una parte dell'utilizzo totale della memoria dell'app. C'è anche l'utilizzo della memoria nativa, che di solito viene utilizzata per pagine Web, giochi e alcuni scopi pesanti. Di solito le app devono cercare solo nella memoria heap, perché è piuttosto bassa rispetto alla RAM del dispositivo e, se la raggiungono, l'app andrà in crash (anche se c'è molta RAM libera).
sviluppatore Android

È uno snippet di codice perfetto, molto utile per controllare l'OOM, grazie mille.
aolphn

@AlphaOF Grazie, ma le cose sono cambiate su Android O. Ho aggiornato la risposta per adattarla alla situazione.
sviluppatore Android il

29

Ecco un modo per calcolare l'utilizzo della memoria dell'applicazione attualmente in esecuzione :

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
È un approccio semplice, ma come è stato indicato nella documentazione, il metodo freeMemory () della classe Runtime, restituisce la memoria disponibile per il programma o l'applicazione corrente. Quindi sii consapevole di ciò durante l'utilizzo.
Aksel Fatih

2
@Peter - Sì, è "sbagliato" in quanto risponde a una domanda diversa da quella che è stata posta. D'altra parte, questo è "giusto" per ciò che uno sviluppatore di app di solito ha bisogno di sapere: raramente importa quale sia lo stato generale della memoria sul DISPOSITIVO - se l'utente ha eseguito molte app, il sistema operativo dovrebbe utilizzarne la maggior parte la sua memoria - altrimenti è inefficiente. Il sistema operativo deve sapere cosa dà la risposta accettata, per sapere quando iniziare a eliminare le app che non sono state utilizzate di recente. Ma un programmatore di app deve sapere cosa ti dice QUESTA risposta (e la risposta simile dello sviluppatore Android), rispetto a runtime.maxMemory.
ToolmakerSteve

Questa soluzione funziona semplicemente sulla memoria esposta all'app da Runtime. Questo non fornisce informazioni sulla memoria dell'intero sistema come richiesto da OP.
AB

Su molti dispositivi (ad esempio Xiaomi) Runtime.freeMemory()restituisce 0 e Runtime.totalMemory()restituisce solo la memoria attualmente allocata.
artem

17

Un altro modo (attualmente mostra 25 MB di spazio libero sul mio G1):

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

Ehi Alex, grazie mille per il tuo aiuto! 1 altra domanda. Questo codice mi dà la RAM disponibile. Voglio anche visualizzare Total RAM. Come ottenerlo?
Badal

@ Badal Non conosco un'API Java per questo. Attenersi all'analisi / proc / meminfo.
yanchenko

12

La filosofia di gestione della memoria di Linux è "La memoria libera è memoria sprecata".

Presumo che le prossime due righe mostreranno quanta memoria è in "Buffers" e quanto è "Cached". Sebbene ci sia una differenza tra i due (per favore non chiedere quale sia la differenza :) entrambi sommano approssimativamente la quantità di memoria utilizzata per memorizzare nella cache i dati dei file e i metadati.

Una guida molto più utile per liberare memoria su un sistema Linux è il free(1)comando; sul mio desktop, riporta informazioni come questa:

$ free -m
             buffer condivisi gratuiti utilizzati totali memorizzati nella cache
Mem: 5980 1055 4924 0 91 374
- / + buffer / cache: 589 5391
Scambio: 6347 0 6347

La linea +/- buffer / cache: è la linea magica, segnala che ho davvero circa 589 mega di memoria di processo attivamente richiesta e circa 5391 mega di memoria 'libera', nel senso che i 91 + 374 megabyte di buffer / memoria cache può essere gettato via se la memoria potesse essere utilizzata in modo più proficuo altrove.

(La mia macchina è in funzione da circa tre ore, senza fare quasi altro che stackoverflow, motivo per cui ho così tanta memoria libera.)

Se Android non viene fornito con free(1), puoi fare i conti da solo con il /proc/meminfofile; Mi piace solo il free(1)formato di output. :)


1
@ Igor, allora vorrai cat /proc/meminfoinvece. È molto più dettagliato, ma MemFree. Bufferse Cachedsono probabilmente le linee più importanti.
sarnold

6

Mi riferisco a pochi scritti.

riferimento:

Questo metodo getMemorySize () viene restituito MemorySize che ha una dimensione di memoria totale e libera.
Non credo perfettamente a questo codice.
Questo codice viene testato su 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;
    }

So che Pattern.compile () è costoso, quindi puoi spostare il suo codice nel membro della classe.


3

Ho guardato Android Source Tree.

All'interno di com.android.server.am. ActivityManagerService.java (servizio interno esposto da 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);
}

All'interno di android.os. Process.java

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

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

Chiama il metodo JNI da android_util_Process.cpp

Conclusione

MemoryInfo.availMem = MemFree + Memorizzato nella cache in / proc / meminfo.

Appunti

La memoria totale viene aggiunta nel livello API 16.


1

puoi anche utilizzare lo strumento DDMS che fa parte di Android SDK stesso. aiuta a ottenere le allocazioni di memoria del codice java e del codice nativo 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;

È un codice strano. Restituisce MaxMemory - (totalMemory - freeMemory). Se freeMemory è uguale a 0, il codice restituirà MaxMemory - totalMemory, quindi può essere maggiore o uguale a 0. Perché freeMemory non viene utilizzato?


0

Ecco un altro modo per visualizzare l'utilizzo della memoria della tua app:

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

Output di esempio:

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

Per l'utilizzo complessivo della memoria:

adb shell dumpsys meminfo

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.