Wie bekomme ich die aktuelle Speichernutzung in Android?

108

Ich habe / proc / meminfo verwendet und die Befehlsantwort analysiert. Das Ergebnis zeigt jedoch Folgendes:

MemTotal: 94348 kB MemFree: 5784 kB

meint. Es zeigt, dass nur 5 MB freier Speicher vorhanden sind. Ist es mit Android Mobile möglich? Auf meinem Handy sind nur 5-6 Anwendungen installiert, und es wird keine andere Aufgabe ausgeführt. Trotzdem zeigt dieser Befehl, dass nur sehr wenig freier Speicher vorhanden ist.

Kann jemand das klären? oder gibt es eine andere Möglichkeit, die Speichernutzung in Android zu erhalten?

Badal
quelle
2
Versuchen Sie, freien Speicher pro Gerät oder pro App anzuzeigen? Wenn pro App, dann muss es auf dem Heap a-la berechnet werden Debug.getNativeHeapFreeSize().
IgorGanapolsky
1
Um den freien Speicher (im RAM) mit / proc / meminfo zu berechnen, müssen Sie das Aggregat aus MemFree , Buffers , Cached und SwapCached abrufen . Zu diesem Zweck wird von Android eine API bereitgestellt, die auf API 16 und auf Stationen funktioniert. Meminfo ist hilfreich, wenn Sie auf ältere APIs abzielen.
AB

Antworten:

174

VORSICHT: Diese Antwort misst die Speichernutzung / Verfügbarkeit des GERÄTS. Dies ist NICHT das, was für Ihre App verfügbar ist. Verwenden Sie die Antwort des Android-Entwicklers, um zu messen, was Ihre APP tut und was dazu berechtigt ist .


Android-Dokumente - ActivityManager.MemoryInfo

  1. Befehl parse / proc / meminfo. Den Referenzcode finden Sie hier: Get Memory Usage in Android

  2. Verwenden Sie den folgenden Code und erhalten Sie den aktuellen 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;

Erläuterung der Nummer 0x100000L

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

1024 * 1024     == 1048576
1048576         == 0x100000

Es ist ziemlich offensichtlich, dass die Zahl verwendet wird, um von Bytes in Mebibyte umzuwandeln

PS: Wir müssen den Gesamtspeicher nur einmal berechnen. Rufen Sie also Punkt 1 nur einmal in Ihrem Code auf und danach können Sie den Code von Punkt 2 wiederholt aufrufen.

Badal
quelle
Ich möchte die Speichergröße überprüfen. Was ist die MemoryInfo?
Piraba
PIraba, seine Android API-Klasse. Überprüfen Sie es hier developer.android.com/reference/android/app/… .
Badal
@SanjayJoshi Das liegt daran, dass die Variable availableMem den Speicher in Bytes enthält. 1024 Bytes entsprechen 1 Kilobyte und 1024 Kilobyte entsprechen 1 MegaByte. Also 1024 * 1024 entspricht 1048576
Rolf
2
Konvertieren Sie in oben verdoppeln, sonst wird ProzentAvail 0 sein
blueether
1
@Rolf ツ Entschuldigung, aber 1024 Bytes entsprechen einem Kibibyte und 1024 Kibibyte sind ein MibiByte. Kilo und Mega sind Dezimalpräfixe. 1000 Byte = 1 Kilobyte. Dies wird auch in der Antwort falsch erklärt.
JacksOnF1re
88

Dies hängt von Ihrer Definition ab, welche Speicherabfrage Sie erhalten möchten.


Normalerweise möchten Sie den Status des Heap-Speichers wissen, da Sie bei zu viel Speicher OOM erhalten und die App zum Absturz bringen.

Dazu können Sie die nächsten Werte überprüfen:

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

Je näher die Variable "usedMemInMB" an "maxHeapSizeInMB" heranrückt, desto näher availHeapSizeInMB kommt sie an Null, desto näher kommt OOM. (Aufgrund der Speicherfragmentierung erhalten Sie möglicherweise OOM, BEVOR dies Null erreicht.)

Das zeigt auch das DDMS-Tool zur Speichernutzung.


Alternativ gibt es die tatsächliche RAM-Auslastung, dh wie viel das gesamte System verbraucht - siehe akzeptierte Antwort, um dies zu berechnen.


Update: Da Android O Ihre App dazu bringt, auch den nativen Arbeitsspeicher (zumindest für den Bitmaps-Speicher, der normalerweise der Hauptgrund für die enorme Speichernutzung ist) und nicht nur den Heap zu verwenden, haben sich die Dinge geändert und Sie erhalten weniger OOM (weil der Der Heap enthält keine Bitmaps mehr (siehe hier ). Sie sollten jedoch die Speichernutzung im Auge behalten, wenn Sie den Verdacht haben, dass Speicherlecks vorliegen. Wenn Sie unter Android O Speicherlecks haben, die bei älteren Versionen zu OOM hätten führen sollen, scheint es, dass es nur abstürzt, ohne dass Sie es abfangen können. So überprüfen Sie die Speichernutzung:

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

Ich glaube jedoch, dass es am besten ist, den Profiler der IDE zu verwenden, der die Daten in Echtzeit mithilfe eines Diagramms anzeigt.

Die gute Nachricht für Android O ist, dass es aufgrund der OOM, zu viele große Bitmaps zu speichern, viel schwieriger ist, Abstürze zu bekommen, aber die schlechte Nachricht ist, dass ich nicht glaube, dass es möglich ist, einen solchen Fall zur Laufzeit zu erfassen.


EDIT: scheint Debug.getNativeHeapSize() sich im Laufe der Zeit zu ändern, da es Ihnen den maximalen Gesamtspeicher für Ihre App anzeigt. Diese Funktionen werden also nur für den Profiler verwendet, um zu zeigen, wie viel Ihre App verwendet.

Wenn Sie den tatsächlichen und verfügbaren nativen RAM erhalten möchten, verwenden Sie Folgendes:

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%)")
Android-Entwickler
quelle
Beeindruckend. So einfach und doch so wahr!
Ran
Was ist die tatsächliche Speichernutzung? also usedMemInMB ist in diesem Fall nicht die reale Speichernutzung der App? Wenn ich diesen Code verwende, wird angezeigt, dass die Auslastung etwa 50 MB beträgt. Wenn ich jedoch zu den Telefoneinstellungen gehe und dort die Speichernutzung sehe, zeigt meine App 100 MB an. Warum ist dieser Unterschied?
Batmaci
1
@batmaci Heap-Speicher ist nur ein Teil der gesamten Speichernutzung der App. Es gibt auch die native Speichernutzung, die normalerweise für Webseiten, Spiele und einige schwere Zwecke verwendet wird. Normalerweise müssen Apps nur auf den Heap-Speicher schauen, da dieser im Vergleich zum Geräte-RAM recht niedrig ist. Wenn sie ihn erreichen, stürzt die App ab (selbst wenn genügend freier RAM vorhanden ist).
Android-Entwickler
Es ist ein perfektes Code-Snippet, sehr nützlich für die Überprüfung von OOM, vielen Dank.
Aolphn
@AlphaOF Vielen Dank, aber unter Android O haben sich die Dinge geändert. Ich habe die Antwort aktualisiert, um sie an die Situation dort anzupassen.
Android-Entwickler
29

Hier ist eine Möglichkeit, die Speichernutzung der aktuell ausgeführten Anwendung zu berechnen :

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
quelle
4
Es ist ein einfacher Ansatz, aber wie in der Dokumentation angegeben, gibt die Runtime-Klasse freeMemory () den verfügbaren Speicher für das aktuelle Programm oder die aktuelle Anwendung zurück. Seien Sie sich dessen während der Verwendung bewusst.
Aksel Fatih
2
@Peter - Ja, es ist "falsch", dass es eine andere Frage beantwortet als gestellt wurde. Auf der anderen Seite ist die „richtige“ für das, was ein App - Entwickler muss in der Regel wissen: es selten zählt , was der Gesamtzustand des Speichers auf dem Gerät - wenn der Benutzer viele Anwendungen ausgeführt wird, das Betriebssystem sollte die Verwendung des meisten macht sein Gedächtnis - sonst ist es ineffizient. Das Betriebssystem muss wissen, was die akzeptierte Antwort gibt, um zu wissen, wann Apps beendet werden müssen, die in letzter Zeit nicht verwendet wurden. Ein App-Programmierer muss jedoch wissen, was DIESE Antwort (und die ähnliche Antwort des Android-Entwicklers) im Vergleich zu runtime.maxMemory sagt.
ToolmakerSteve
Diese Lösung funktioniert lediglich mit dem Speicher, der von Runtime für die App verfügbar gemacht wird. Dies gibt keinen Einblick in den gesamten Systemspeicher, wie es OP erfordert.
AB
Auf vielen Geräten (z. B. Xiaomi) wird Runtime.freeMemory()0 und nur Runtime.totalMemory()der aktuell zugewiesene Speicher zurückgegeben.
Artem
17

Ein anderer Weg (zeigt derzeit 25 MB frei auf meinem G1):

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
yanchenko
quelle
Hey Alex, vielen Dank für deine Hilfe! 1 weitere Frage. Dieser Code gibt mir verfügbaren RAM. Ich möchte auch Total RAM anzeigen. Wie bekomme ich das?
Badal
@Badal Ich kenne keine Java-API dafür. Halten Sie sich an parsing / proc / meminfo.
Yanchenko
12

Die Speicherverwaltungsphilosophie von Linux lautet "Freier Speicher ist verschwendeter Speicher".

Ich gehe davon aus, dass die nächsten beiden Zeilen zeigen, wie viel Speicher in "Puffern" und wie viel "zwischengespeichert" ist. Obwohl es einen Unterschied zwischen den beiden gibt (bitte fragen Sie nicht, was dieser Unterschied ist :), addieren sich beide ungefähr zu der Menge an Speicher, die zum Zwischenspeichern von Dateidaten und Metadaten verwendet wird.

Eine weitaus nützlichere Anleitung zum Freigeben von Speicher auf einem Linux-System ist der free(1)Befehl. Auf meinem Desktop werden folgende Informationen angezeigt:

$ free -m
             Insgesamt verwendete kostenlose gemeinsam genutzte Puffer im Cache
Mem: 5980 1055 4924 0 91 374
- / + Puffer / Cache: 589 5391
Swap: 6347 0 6347

Die +/- Puffer / Cache: -Linie ist die magische Linie. Sie gibt an, dass ich wirklich ungefähr 589 Megabyte aktiv benötigten Prozessspeicher und ungefähr 5391 Megabyte 'freien' Speicher in dem Sinne habe, dass die 91 + 374 Megabyte von Puffern / zwischengespeichertem Speicher kann weggeworfen werden, wenn der Speicher an anderer Stelle rentabler verwendet werden könnte.

(Mein Computer ist seit ungefähr drei Stunden in Betrieb und hat fast nichts als einen Stapelüberlauf ausgeführt, weshalb ich so viel freien Speicher habe.)

Wenn Android nicht mit ausgeliefert wird free(1), können Sie die Berechnung selbst mit der /proc/meminfoDatei durchführen. Ich mag nur das free(1)Ausgabeformat. :) :)

Sarnold
quelle
1
@Igor, dann willst du cat /proc/meminfostattdessen. Es ist viel detaillierter, aber MemFree. Buffersund Cachedsind wahrscheinlich die wichtigsten Zeilen.
Sarnold
6

Ich beziehe mich auf einige Schriften.

Referenz:

Diese getMemorySize () -Methode wird als MemorySize zurückgegeben, die eine Gesamtgröße und eine freie Speichergröße aufweist.
Ich glaube diesen Code nicht perfekt.
Dieser Code wird auf LG G3 Kat.6 (v5.0.1) getestet.

    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;
    }

Ich weiß, dass Pattern.compile () teure Kosten verursacht, sodass Sie den Code möglicherweise in ein Klassenmitglied verschieben können.

Hogun
quelle
3

Ich habe mir Android Source Tree angesehen.

In com.android.server.am. ActivityManagerService.java (interner Dienst, der von android.app. ActivityManager verfügbar gemacht wird ).

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);
}

In android.os. Process.java

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

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

Es ruft die JNI-Methode von android_util_Process.cpp auf

Fazit

MemoryInfo.availMem = MemFree + Zwischengespeichert in / proc / meminfo.

Anmerkungen

Der Gesamtspeicher wird in API-Ebene 16 hinzugefügt.

Ragazenta
quelle
1

Sie können auch das DDMS-Tool verwenden, das Teil des Android SDK selbst ist. Es hilft auch dabei, Speicherzuordnungen für Java-Code und nativen C / C ++ - Code zu erhalten.

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

Es ist ein seltsamer Code. Es gibt MaxMemory - (totalMemory - freeMemory) zurück. Wenn freeMemory gleich 0 ist, gibt der Code MaxMemory - totalMemory zurück, sodass mehr oder gleich 0 sein kann. Warum wird freeMemory nicht verwendet?

Andrey
quelle
0

Hier ist eine andere Möglichkeit, die Speichernutzung Ihrer App anzuzeigen:

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

Beispielausgabe:

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

Für die allgemeine Speichernutzung:

adb shell dumpsys meminfo

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

user1506104
quelle