Como obter o uso de memória atual no Android?

108

Usei / proc / meminfo e analisei a resposta do comando. No entanto, o resultado mostra que:

MemTotal: 94348 kB MemFree: 5784 kB

significa. mostra que há apenas 5 MB de memória livre. É possível com o Android móvel? Há apenas 5-6 aplicativos instalados no meu celular e nenhuma outra tarefa está em execução. mas ainda assim este comando mostra que há muito pouca memória livre.

Alguém pode esclarecer isso? ou existe alguma outra maneira de obter o uso de memória no Android?

Badal
fonte
2
Você está tentando ver a memória livre por dispositivo ou por aplicativo? Se for por aplicativo, ele precisa ser calculado no heap a-la Debug.getNativeHeapFreeSize().
IgorGanapolsky
1
Para calcular a memória livre (na RAM) usando / proc / meminfo, você deve obter o agregado de MemFree , Buffers , Cached e SwapCached . Existe uma API para essa finalidade fornecida pelo Android que funciona na API 16 e em wards. Meminfo é útil se você estiver direcionando APIs mais antigas.
AB

Respostas:

174

CUIDADO: Esta resposta mede o uso / disponibilidade da memória do DISPOSITIVO. NÃO é isso que está disponível para seu aplicativo. Para medir o que seu APP está fazendo e tem permissão para fazer, use a resposta do desenvolvedor do Android .


Documentos Android - ActivityManager.MemoryInfo

  1. comando parse / proc / meminfo. Você pode encontrar o código de referência aqui: Obtenha o uso da memória no Android

  2. use o código abaixo e obtenha RAM atual:

    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;

Explicação do número 0x100000L

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

1024 * 1024     == 1048576
1048576         == 0x100000

É bastante óbvio que o número é usado para converter de bytes em mebibyte

PS: precisamos calcular a memória total apenas uma vez. então chame o ponto 1 apenas uma vez em seu código e depois, você pode chamar o código do ponto 2 repetidamente.

Badal
fonte
Quero verificar o tamanho da memória. O que é MemoryInfo?
Piraba
PIraba, sua classe API android. Verifique aqui developer.android.com/reference/android/app/… .
Badal de
@SanjayJoshi Isso ocorre porque a variável availMem contém a memória em bytes. 1024 bytes equivalem a 1 quilobyte e 1024 kilobytes equivalem a 1 megabyte. Portanto, 1024 * 1024 é igual a 1048576
Rolf ツ
2
Converta para o dobro acima, caso contrário, a porcentagem de velocidade será 0
azul de
1
@Rolf ツ desculpe, mas 1024 bytes equivalem a um Kibibyte e 1024 Kibibyte são um MibiByte. Kilo e Mega são prefixos decimais. 1000 bytes = 1 kilobyte. Isso também está errado, explicado na resposta.
JacksOnF1re
88

Depende da sua definição de qual consulta de memória você deseja obter.


Normalmente, você gostaria de saber o status da memória heap, uma vez que se ela usar muita memória, você obtém OOM e falha o aplicativo.

Para isso, você pode verificar os próximos 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;

Quanto mais a variável "usedMemInMB" se aproxima de "maxHeapSizeInMB", quanto mais perto availHeapSizeInMBchega de zero, mais perto você obtém OOM. (Devido à fragmentação da memória, você pode obter OOM ANTES de chegar a zero.)

Isso também é o que mostra a ferramenta DDMS de uso de memória.


Alternativamente, existe o uso real de RAM, que é quanto todo o sistema usa - veja a resposta aceita para calcular isso.


Atualização: como o Android O faz seu aplicativo também usar a RAM nativa (pelo menos para armazenamento de bitmaps, que geralmente é o principal motivo para o uso excessivo de memória), e não apenas o heap, as coisas mudaram e você obtém menos OOM (porque o heap não contém mais bitmaps, verifique aqui ), mas você ainda deve ficar de olho no uso da memória se suspeitar que há vazamentos de memória. No Android O, se você tiver vazamentos de memória que deveriam ter causado OOM em versões mais antigas, parece que ele irá travar sem que você consiga detectá-lo. Veja como verificar o uso de memória:

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

Mas acredito que seja melhor usar o profiler do IDE, que mostra os dados em tempo real, usando um gráfico.

Portanto, a boa notícia no Android O é que é muito mais difícil travar devido ao OOM de armazenar muitos bitmaps grandes, mas a má notícia é que não acho que seja possível detectar tal caso durante o tempo de execução.


EDIT: parece Debug.getNativeHeapSize()mudar com o tempo, pois mostra a memória máxima total para seu aplicativo. Portanto, essas funções são usadas apenas para o criador de perfil, para mostrar o quanto seu aplicativo está usando.

Se você deseja obter o total real e a RAM nativa disponível, use:

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%)")
desenvolvedor android
fonte
Uau. Tão simples, mas tão verdadeiro!
Executado em
qual é o uso real de memória? então usedMemInMB, neste caso, não é o uso real de memória do aplicativo? Quando eu uso esse código, ele mostra que o uso é de 50 MB, mas quando vou para as configurações do telefone e vejo o uso de memória lá, meu aplicativo mostra 100 MB. por que essa diferença?
batmaci
1
@batmaci A memória heap é apenas uma parte do uso total de memória do aplicativo. Há também o uso de memória nativa, que normalmente é usada para páginas da Web, jogos e alguns fins pesados. Normalmente, os aplicativos precisam olhar apenas na memória heap, porque é muito baixa em comparação com a RAM do dispositivo e, se eles chegarem a ela, o aplicativo irá travar (mesmo se houver bastante RAM livre).
Desenvolvedor Android
É um trecho de código perfeito, muito útil para verificar OOM, muito obrigado.
aolphn
@AlphaOF Obrigado, mas as coisas mudaram no Android O. Atualizei a resposta para corresponder à situação lá.
desenvolvedor Android
29

Esta é uma maneira de calcular o uso de memória do aplicativo em execução :

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
fonte
4
É uma abordagem simples, mas como foi indicado na documentação, o método freeMemory () da classe Runtime retorna a memória disponível para o programa ou aplicativo atual. Portanto, esteja ciente disso ao usar.
Aksel Fatih
2
@Peter - Sim, está "errado" porque responde a uma pergunta diferente da que foi feita. Por outro lado, isso é "certo" para o que um desenvolvedor de aplicativos geralmente precisa saber: raramente importa qual é o estado geral da memória no DISPOSITIVO - se o usuário executou muitos aplicativos, o sistema operacional deve usar a maioria deles sua memória - caso contrário, está sendo ineficiente. OS precisa saber o que a resposta aceita dá, para saber quando começar a matar aplicativos que não foram usados ​​recentemente. Mas um programador de aplicativo precisa saber o que ESTA resposta (e a resposta semelhante do desenvolvedor do Android) diz a você, em comparação com runtime.maxMemory.
ToolmakerSteve
Esta solução funciona apenas na memória exposta ao aplicativo pelo Runtime. Isso não fornece uma visão sobre a memória do sistema inteiro, conforme requer o OP.
AB
Em muitos dispositivos (por exemplo, Xiaomi) Runtime.freeMemory()retorna 0 e Runtime.totalMemory()retorna apenas a memória atualmente alocada.
artem
17

Outra forma (atualmente mostrando 25 MB livres no meu G1):

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
Yanchenko
fonte
Ei Alex, Muito obrigado pela sua ajuda! Mais 1 pergunta. Este código me fornece RAM disponível. Também quero exibir RAM total. Como conseguir isso?
Badal
@Badal Não conheço uma API Java para isso. Limite-se a analisar / proc / meminfo.
yanchenko
12

A filosofia de gerenciamento de memória do Linux é "Memória livre é memória desperdiçada".

Presumo que as próximas duas linhas mostrarão quanta memória há em "Buffers" e quanta está em "Cache". Embora haja uma diferença entre os dois (por favor, não pergunte qual é essa diferença :) ambos somam aproximadamente a quantidade de memória usada para armazenar dados e metadados do arquivo em cache.

Um guia muito mais útil para liberar memória em um sistema Linux é o free(1)comando; na minha área de trabalho, ele relata informações como esta:

$ free -m
             total de buffers compartilhados gratuitos usados ​​em cache
Mem: 5980 1055 4924 0 91 374
- / + buffers / cache: 589 5391
Troca: 6347 0 6347

A linha +/- buffers / cache: é a linha mágica, ela relata que eu realmente tenho cerca de 589 megs de memória de processo ativamente exigida e cerca de 5391 megs de memória 'livre', no sentido de que os 91 + 374 megabytes de buffers / memória em cache podem ser descartados se a memória pudesse ser usada de forma mais lucrativa em outro lugar.

(Minha máquina está ligada há cerca de três horas, fazendo quase nada além de stackoverflow, e é por isso que tenho tanta memória livre.)

Se o Android não for fornecido free(1), você mesmo pode fazer as contas com o /proc/meminfoarquivo; Eu apenas gosto do free(1)formato de saída. :)

Sarnold
fonte
1
@Igor, então você vai querer cat /proc/meminfo. É muito mais detalhado, mas MemFree. Bufferse Cachedsão provavelmente as linhas mais importantes.
sarnold de
6

Refiro-me a alguns escritos.

referência:

Este método getMemorySize () é retornado como MemorySize com tamanho de memória total e livre.
Eu não acredito neste código perfeitamente.
Este código está sendo testado no 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;
    }

Eu sei que Pattern.compile () tem um custo caro, então você pode mover seu código para o membro da classe.

Hogun
fonte
3

Eu olhei para Android Source Tree.

Dentro de com.android.server.am. ActivityManagerService.java (serviço interno exposto 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();

Ele chama o método JNI de android_util_Process.cpp

Conclusão

MemoryInfo.availMem = MemFree + Armazenado em cache em / proc / meminfo.

Notas

Memória total é adicionada no nível 16 da API.

ragazenta
fonte
1

você também pode usar a ferramenta DDMS que faz parte do próprio SDK do Android. ele ajuda a obter alocações de memória de código java e código c / c ++ nativo também.

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

É um código estranho. Ele retorna MaxMemory - (totalMemory - freeMemory). Se freeMemory for igual a 0, o código retornará MaxMemory - totalMemory, portanto, pode ser maior ou igual a 0. Por que freeMemory não foi usado?

Andrey
fonte
0

Esta é outra maneira de visualizar o uso de memória do seu aplicativo:

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

Saída de amostra:

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 uso geral de memória:

adb shell dumpsys meminfo

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

user1506104
fonte