Comment obtenir l'utilisation actuelle de la mémoire dans Android?


108

J'ai utilisé / proc / meminfo et analysé la réponse de la commande, mais le résultat montre que:

MemTotal: 94348 kB MemFree: 5784 kB

veux dire. cela montre qu'il n'y a que 5 Mo de mémoire libre. Est-ce possible avec Android mobile? Il n'y a que 5-6 applications installées sur mon mobile et aucune autre tâche n'est en cours d'exécution. mais cette commande montre toujours qu'il y a très peu de mémoire libre.

Quelqu'un peut-il clarifier cela? ou y a-t-il un autre moyen d'utiliser la mémoire sous Android?


2
Essayez-vous de voir la mémoire libre par appareil ou par application? Si par application, il doit être calculé sur le tas a-la Debug.getNativeHeapFreeSize().
IgorGanapolsky

1
Pour calculer la mémoire libre (en RAM) en utilisant / proc / meminfo, vous devez obtenir l'agrégat de MemFree , Buffers , Cached et SwapCached . Il existe une API à cet effet fournie par Android qui fonctionne sur l'API 16 et sur les wards. Meminfo est utile si vous ciblez des API plus anciennes.
AB

Réponses:


174

ATTENTION: Cette réponse mesure l'utilisation de la mémoire / disponible du PÉRIPHÉRIQUE. Ce n'est PAS ce qui est disponible pour votre application. Pour mesurer ce que fait votre application et est AUTORISÉ à le faire, utilisez la réponse du développeur Android .


Documents Android - ActivityManager.MemoryInfo

  1. parse / proc / meminfo commande. Vous pouvez trouver le code de référence ici: Obtenir l'utilisation de la mémoire dans Android

  2. utilisez le code ci-dessous et obtenez la RAM actuelle:

    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;

Explication du nombre 0x100000L

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

1024 * 1024     == 1048576
1048576         == 0x100000

Il est assez évident que le nombre est utilisé pour convertir des octets en mégaoctets

PS: nous n'avons besoin de calculer la mémoire totale qu'une seule fois. donc n'appelez le point 1 qu'une seule fois dans votre code, puis après, vous pouvez appeler le code du point 2 de manière répétitive.


Je veux vérifier la taille de la mémoire. Qu'est-ce que MemoryInfo?
Piraba

PIraba, sa classe d'API android. Vérifiez-le ici developer.android.com/reference/android/app/… .
Badal

@SanjayJoshi C'est parce que la variable availableMem contient la mémoire en octets. 1024 octets équivaut à 1 kilo-octet et 1024 kilo-octets équivaut à 1 mégaoctet. Donc 1024 * 1024 équivaut à 1048576
Rolf ツ

2
Convertir pour doubler ci-dessus, sinon percentAvail sera 0
blueether

1
@Rolf ツ désolé mais 1024 octets équivaut à un Kibibyte et 1024 Kibibyte sont un MibiByte. Kilo et Mega sont des préfixes décimaux. 1000 octets = 1 kilo-octet. Ceci est également mal expliqué dans la réponse.
JacksOnF1re

88

Cela dépend de votre définition de la requête mémoire que vous souhaitez obtenir.


Habituellement, vous souhaitez connaître l'état de la mémoire du tas, car si elle utilise trop de mémoire, vous obtenez un MOO et plantez l'application.

Pour cela, vous pouvez vérifier les valeurs suivantes:

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

Plus la variable "usedMemInMB" se rapproche de "maxHeapSizeInMB", plus availHeapSizeInMBse rapproche de zéro, plus vous vous rapprochez du MOO. (En raison de la fragmentation de la mémoire, vous pouvez obtenir OOM AVANT que cela n'atteigne zéro.)

C'est aussi ce que montre l'outil DDMS d'utilisation de la mémoire.


Alternativement, il y a l'utilisation réelle de la RAM, qui est la quantité utilisée par le système entier - voir la réponse acceptée pour calculer cela.


Mise à jour: depuis Android O fait que votre application utilise également la RAM native (au moins pour le stockage Bitmaps, qui est généralement la principale raison de l'utilisation énorme de la mémoire), et pas seulement le tas, les choses ont changé et vous obtenez moins de MOO (car le heap ne contient plus de bitmaps, vérifiez ici ), mais vous devriez toujours garder un œil sur l'utilisation de la mémoire si vous pensez avoir des fuites de mémoire. Sur Android O, si vous avez des fuites de mémoire qui auraient dû provoquer un MOO sur les anciennes versions, il semble qu'il se plantera sans que vous puissiez l'attraper. Voici comment vérifier l'utilisation de la mémoire:

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

Mais je pense qu'il serait peut-être préférable d'utiliser le profileur de l'EDI, qui affiche les données en temps réel, à l'aide d'un graphique.

Donc, la bonne nouvelle sur Android O est qu'il est beaucoup plus difficile d'obtenir des plantages en raison du stockage de trop de bitmaps volumineux par MOO, mais la mauvaise nouvelle est que je ne pense pas qu'il soit possible de détecter un tel cas pendant l'exécution.


EDIT: semble Debug.getNativeHeapSize()changer au fil du temps, car il vous montre la mémoire maximale totale de votre application. Donc, ces fonctions ne sont utilisées que pour le profileur, pour montrer combien votre application utilise.

Si vous souhaitez obtenir la RAM native totale réelle et disponible, utilisez ceci:

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

Sensationnel. Si simple, mais si vrai!
couru le

quelle est l'utilisation réelle de la mémoire? donc usedMemInMB dans ce cas n'est pas une utilisation réelle de la mémoire de l'application? Lorsque j'utilise ce code, il me montre que l'utilisation est de 50 Mo, mais lorsque je vais dans les paramètres du téléphone et que je vois l'utilisation de la mémoire, mon application affiche 100 Mo. pourquoi cette différence?
batmaci

1
La mémoire @batmaci Heap n'est qu'une partie de l'utilisation totale de la mémoire de l'application. Il y a aussi l'utilisation de la mémoire native, qui est généralement utilisée pour les pages Web, les jeux et certains objectifs lourds. Habituellement, les applications ne doivent regarder que sur la mémoire du tas, car elle est assez faible par rapport à la RAM de l'appareil, et si elles l'atteignent, l'application plantera (même s'il y a beaucoup de RAM libre).
développeur android

C'est un extrait de code parfait, très utile pour vérifier MOO, merci beaucoup.
aolphn

@AlphaOF Merci, mais les choses ont changé sur Android O. J'ai mis à jour la réponse pour correspondre à la situation là-bas.
développeur android

29

Voici un moyen de calculer l'utilisation de la mémoire de l'application en cours d'exécution :

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
C'est une approche simple, mais comme cela a été indiqué dans la documentation, la méthode freeMemory () de la classe Runtime, retourne la mémoire disponible pour le programme ou l'application en cours. Soyez donc conscient de cela lors de l'utilisation.
Aksel Fatih

2
@Peter - Oui, c'est "faux" en ce sens qu'il répond à une question différente de celle qui a été posée. D'un autre côté, c'est «juste» pour ce qu'un développeur d'applications a généralement besoin de savoir: l'état général de la mémoire de l'APPAREIL importe rarement - si l'utilisateur a exécuté de nombreuses applications, le système d'exploitation devrait utiliser la plupart des sa mémoire - sinon il est inefficace. Le système d'exploitation doit savoir ce que donne la réponse acceptée, pour savoir quand commencer à tuer les applications qui n'ont pas été utilisées récemment. Mais un programmeur d'application doit savoir ce que cette réponse (et la réponse similaire du développeur Android) vous dit, par rapport à runtime.maxMemory.
ToolmakerSteve

Cette solution fonctionne simplement sur la mémoire exposée à l'application par Runtime. Cela ne donne pas un aperçu de la mémoire système entière comme OP l'exige.
AB

Sur de nombreux appareils (par exemple Xiaomi) Runtime.freeMemory()renvoie 0 et Runtime.totalMemory()renvoie uniquement la mémoire actuellement allouée.
artem

17

Une autre façon (montrant actuellement 25 Mo gratuits sur mon G1):

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

Hey Alex, merci beaucoup pour votre aide! Encore une question. Ce code me donne de la RAM disponible. Je souhaite également afficher la RAM totale. Comment l'obtenir?
Badal

@Badal Je ne connais pas d'API Java pour ça. Tenez-vous-en à l'analyse de / proc / meminfo.
yanchenko

12

La philosophie de gestion de la mémoire de Linux est «La mémoire libre est de la mémoire gaspillée».

Je suppose que les deux prochaines lignes montreront la quantité de mémoire dans "Buffers" et la quantité de "Cached". Bien qu'il y ait une différence entre les deux (veuillez ne pas demander quelle est cette différence :), ils ajoutent tous les deux à la quantité de mémoire utilisée pour mettre en cache les données et les métadonnées des fichiers.

Un guide bien plus utile pour libérer de la mémoire sur un système Linux est la free(1)commande; sur mon bureau, il rapporte des informations comme celle-ci:

$ gratuit -m
             total des tampons partagés gratuits utilisés mis en cache
Mem: 5980 1055 4924 0 91374
- / + tampons / cache: 589 5391
Échanger: 6347 0 6347

La ligne +/- buffers / cache: est la ligne magique, elle rapporte que j'ai vraiment environ 589 Mo de mémoire de processus activement requise, et environ 5391 Mo de mémoire `` libre '', dans le sens où les 91 + 374 mégaoctets des tampons / mémoire cache peuvent être jetés si la mémoire peut être utilisée de manière plus rentable ailleurs.

(Ma machine a fonctionné pendant environ trois heures, ne faisant presque rien d'autre que stackoverflow, c'est pourquoi j'ai autant de mémoire libre.)

Si Android n'est pas livré avec free(1), vous pouvez faire le calcul vous-même avec le /proc/meminfofichier; J'aime juste le free(1)format de sortie. :)


1
@Igor, alors vous voudrez cat /proc/meminfoplutôt le faire. C'est beaucoup plus détaillé, mais MemFree. Buffers, et Cachedsont probablement les lignes les plus importantes.
sarnold

6

Je me réfère à quelques écrits.

référence:

Cette méthode getMemorySize () est renvoyée MemorySize qui a une taille de mémoire totale et libre.
Je ne crois pas parfaitement ce code.
Ce code teste sur 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;
    }

Je sais que Pattern.compile () coûte cher, vous pouvez donc déplacer son code vers un membre de classe.


3

J'ai regardé l'arbre des sources Android.

À l'intérieur de com.android.server.am. ActivityManagerService.java (service interne exposé par 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);
}

Dans android.os. Process.java

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

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

Il appelle la méthode JNI à partir de android_util_Process.cpp

Conclusion

MemoryInfo.availMem = MemFree + mis en cache dans / proc / meminfo.

Remarques

La mémoire totale est ajoutée au niveau d'API 16.


1

vous pouvez également utiliser l'outil DDMS qui fait partie du SDK Android lui-même. il aide également à obtenir des allocations de mémoire de code java et de code c / c ++ natif.


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;

C'est un code étrange. Il renvoie MaxMemory - (totalMemory - freeMemory). Si freeMemory vaut 0, alors le code renverra MaxMemory - totalMemory, donc il peut être supérieur ou égal à 0. Pourquoi freeMemory n'est-il pas utilisé?


0

Voici une autre façon d'afficher l'utilisation de la mémoire de votre application:

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

Exemple de sortie:

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

Pour l'utilisation globale de la mémoire:

adb shell dumpsys meminfo

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.