Wie kann ich den in meiner Android-Anwendung verwendeten Speicher programmgesteuert finden?
Ich hoffe, es gibt einen Weg, dies zu tun. Und wie bekomme ich auch den freien Speicher des Telefons?
java
android
memory
memory-management
Andrea Baccega
quelle
quelle
Antworten:
Beachten Sie, dass die Speichernutzung unter modernen Betriebssystemen wie Linux ein äußerst komplizierter und schwer verständlicher Bereich ist. Tatsächlich ist die Wahrscheinlichkeit, dass Sie die Zahlen, die Sie erhalten, tatsächlich richtig interpretieren, äußerst gering. (Fast jedes Mal, wenn ich mit anderen Ingenieuren die Speichernutzungszahlen betrachte, gibt es eine lange Diskussion darüber, was sie tatsächlich bedeuten, was nur zu einer vagen Schlussfolgerung führt.)
Hinweis: Wir haben jetzt eine viel umfangreichere Dokumentation zum Verwalten des Speichers Ihrer App, die einen Großteil des Materials hier abdeckt und mit dem Status von Android auf dem neuesten Stand ist.
Als erstes sollten Sie wahrscheinlich den letzten Teil dieses Artikels lesen, in dem erläutert wird, wie der Speicher unter Android verwaltet wird:
Änderungen der Service-API ab Android 2.0
Jetzt
ActivityManager.getMemoryInfo()
ist unsere API auf höchster Ebene für die Betrachtung der gesamten Speichernutzung. Dies dient hauptsächlich dazu, einer Anwendung zu helfen, zu beurteilen, wie nahe das System daran ist, keinen Speicher mehr für Hintergrundprozesse zu haben, und daher damit beginnen muss, benötigte Prozesse wie Dienste zu beenden. Für reine Java-Anwendungen sollte dies wenig nützlich sein, da das Java-Heap-Limit teilweise dazu dient, zu verhindern, dass eine App das System bis zu diesem Punkt belasten kann.Auf einer niedrigeren Ebene können Sie die Debug-API verwenden, um Informationen auf Kernel-Ebene zur Speichernutzung abzurufen : android.os.Debug.MemoryInfo
Beachten Sie, dass es ab 2.0 auch eine API gibt
ActivityManager.getProcessMemoryInfo
, um diese Informationen zu einem anderen Prozess abzurufen : ActivityManager.getProcessMemoryInfo (int [])Dies gibt eine Low-Level-MemoryInfo-Struktur mit all diesen Daten zurück:
Aber, was ist der Unterschied zwischen
Pss
,PrivateDirty
undSharedDirty
... na ja jetzt beginnt der Spaß.Viel Speicher in Android (und Linux-Systemen im Allgemeinen) wird tatsächlich von mehreren Prozessen gemeinsam genutzt. Wie viel Speicher ein Prozess verwendet, ist also nicht klar. Fügen Sie zusätzlich dieses Paging auf die Festplatte hinzu (geschweige denn Swap, das wir unter Android nicht verwenden), und es ist noch weniger klar.
Wenn Sie also den gesamten physischen RAM verwenden würden, der tatsächlich jedem Prozess zugeordnet ist, und alle Prozesse addieren würden, würden Sie wahrscheinlich eine Zahl erhalten, die viel größer ist als der tatsächliche Gesamtspeicher.
Die
Pss
Anzahl ist eine vom Kernel berechnete Metrik, die die Speicherfreigabe berücksichtigt. Grundsätzlich wird jede Seite des Arbeitsspeichers in einem Prozess durch ein Verhältnis der Anzahl anderer Prozesse skaliert, die diese Seite ebenfalls verwenden. Auf diese Weise können Sie (theoretisch) das PSS über alle Prozesse hinweg addieren, um den von ihnen verwendeten Gesamtspeicher zu sehen, und das PSS zwischen Prozessen vergleichen, um eine grobe Vorstellung von ihrem relativen Gewicht zu erhalten.Die andere interessante Metrik hier ist
PrivateDirty
im Grunde die Menge an RAM innerhalb des Prozesses, die nicht auf die Festplatte ausgelagert werden kann (sie wird nicht von denselben Daten auf der Festplatte unterstützt) und nicht mit anderen Prozessen gemeinsam genutzt wird. Eine andere Möglichkeit, dies zu betrachten, ist der RAM, der dem System zur Verfügung steht, wenn dieser Prozess unterbrochen wird (und wahrscheinlich schnell in Caches und andere Verwendungen davon zusammengefasst wird).Das sind so ziemlich die SDK-APIs dafür. Sie können als Entwickler jedoch noch mehr mit Ihrem Gerät tun.
Mit
adb
können Sie viele Informationen über die Speichernutzung eines laufenden Systems abrufen. Ein häufiger Befehl ist der Befehl,adb shell dumpsys meminfo
der eine Reihe von Informationen über die Speichernutzung jedes Java-Prozesses ausspuckt, die die oben genannten Informationen sowie eine Vielzahl anderer Dinge enthalten. Sie können auch den Namen oder die PID eines einzelnen Prozesses eingeben, um beispielsweiseadb shell dumpsys meminfo system
den Systemprozess zu sehen:Der obere Abschnitt ist die wichtigste, wo
size
ist die Gesamtgröße in Adressraum eines bestimmten Haufens,allocated
ist die kb Istverrechnungen dass Haufen denken , es hat,free
ist der restliche kb des Heap frei für zusätzliche Zuteilungen hat, undpss
undpriv dirty
ist die gleiche wie zuvor speziell für Seiten beschrieben, die jedem der Heaps zugeordnet sind.Wenn Sie nur die Speichernutzung über alle Prozesse hinweg betrachten möchten, können Sie den Befehl verwenden
adb shell procrank
. Die Ausgabe auf demselben System sieht folgendermaßen aus:Hier sind die Spalten
Vss
undRss
im Grunde genommen Rauschen (dies sind der einfache Adressraum und die RAM-Auslastung eines Prozesses. Wenn Sie die RAM-Auslastung prozessübergreifend addieren, erhalten Sie eine lächerlich große Zahl).Pss
ist wie wir vorher gesehen haben undUss
istPriv Dirty
.Interessantes zu beachten:
Pss
und unterscheidenUss
sich geringfügig (oder mehr als geringfügig) von dem, was wir gesehen habenmeminfo
. Warum ist das so? Nun, Procrank verwendet einen anderen Kernel-Mechanismus, um seine Daten zu sammeln als dies dermeminfo
Fall ist, und sie liefern leicht unterschiedliche Ergebnisse. Warum ist das so? Ehrlich gesagt habe ich keine Ahnung. Ich glaube, esprocrank
mag genauer sein ... aber wirklich, das lässt nur den Punkt: "Nehmen Sie alle Erinnerungsinformationen, die Sie mit einem Salzkorn erhalten; oft ein sehr großes Korn."Schließlich gibt es den Befehl
adb shell cat /proc/meminfo
, der eine Zusammenfassung der gesamten Speichernutzung des Systems gibt. Hier gibt es viele Daten, nur die ersten Zahlen, die es wert sind, diskutiert zu werden (und die übrigen, die von wenigen Menschen verstanden werden, und meine Fragen an diese wenigen Menschen, die oft zu widersprüchlichen Erklärungen führen):MemTotal
ist die Gesamtmenge an Speicher, die dem Kernel und dem Benutzerbereich zur Verfügung steht (häufig weniger als der tatsächliche physische RAM des Geräts, da ein Teil dieses RAM für das Radio, DMA-Puffer usw. benötigt wird).MemFree
ist die Menge an RAM, die überhaupt nicht verwendet wird. Die Zahl, die Sie hier sehen, ist sehr hoch; Auf einem Android-System sind dies normalerweise nur wenige MB, da wir versuchen, den verfügbaren Speicher zu verwenden, um die Prozesse am Laufen zu haltenCached
ist der RAM, der für Dateisystem-Caches und andere solche Dinge verwendet wird. Typische Systeme benötigen ungefähr 20 MB, um nicht in einen schlechten Paging-Zustand zu geraten. Der Android Out-of-Memory-Killer ist auf ein bestimmtes System abgestimmt, um sicherzustellen, dass Hintergrundprozesse beendet werden, bevor der zwischengespeicherte RAM von ihnen zu stark beansprucht wird, um zu einem solchen Paging zu führen.quelle
Ja, Sie können Speicherinformationen programmgesteuert abrufen und entscheiden, ob Sie speicherintensive Arbeiten ausführen möchten.
Holen Sie sich die VM-Heap-Größe, indem Sie Folgendes aufrufen:
Holen Sie sich den zugewiesenen VM-Speicher, indem Sie Folgendes aufrufen:
Holen Sie sich das VM Heap Size Limit, indem Sie Folgendes aufrufen:
Holen Sie sich den nativ zugewiesenen Speicher, indem Sie Folgendes aufrufen:
Ich habe eine App erstellt, um das Verhalten von OutOfMemoryError herauszufinden und die Speichernutzung zu überwachen.
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
Den Quellcode erhalten Sie unter https://github.com/coocood/oom-research
quelle
Dies ist eine laufende Arbeit, aber das verstehe ich nicht:
Warum wird die PID nicht dem Ergebnis in activityManager.getProcessMemoryInfo () zugeordnet? Natürlich möchten Sie die resultierenden Daten aussagekräftig machen. Warum hat Google es so schwierig gemacht, die Ergebnisse zu korrelieren? Das aktuelle System funktioniert nicht einmal gut, wenn ich die gesamte Speichernutzung verarbeiten möchte, da das zurückgegebene Ergebnis ein Array von android.os.Debug.MemoryInfo-Objekten ist, aber keines dieser Objekte sagt Ihnen tatsächlich, welchen Pids sie zugeordnet sind. Wenn Sie einfach ein Array aller Pids übergeben, können Sie die Ergebnisse nicht verstehen. Soweit ich weiß, ist es sinnlos, mehr als eine PID gleichzeitig zu übergeben. Wenn dies der Fall ist, warum sollte es dann so gemacht werden, dass activityManager.getProcessMemoryInfo () nur ein int-Array akzeptiert?
quelle
Hackbod's ist eine der besten Antworten auf Stack Overflow. Es wirft ein Licht auf ein sehr dunkles Thema. Es hat mir sehr geholfen.
Eine weitere wirklich hilfreiche Ressource ist dieses Video, das man gesehen haben muss: Google I / O 2011: Speicherverwaltung für Android Apps
AKTUALISIEREN:
Process Stats, ein Dienst, mit dem Sie herausfinden können , wie Ihre App den Speicher verwaltet, wird im Blogbeitrag erläutert. Process Stats: Verstehen, wie Ihre App RAM verwendet von Dianne Hackborn:
quelle
Android Studio 0.8.10+ hat ein unglaublich nützliches Tool namens Memory Monitor eingeführt .
Wofür es gut ist:
Abbildung 1. Erzwingen eines GC-Ereignisses (Garbage Collection) auf dem Android Memory Monitor
Mithilfe dieser Funktion können Sie in Echtzeit zahlreiche gute Informationen zum RAM-Verbrauch Ihrer App erhalten.
quelle
1) Ich denke nicht, zumindest nicht von Java.
2)
quelle
Wir haben herausgefunden, dass alle Standardmethoden zum Abrufen des Gesamtspeichers des aktuellen Prozesses einige Probleme aufweisen.
Runtime.getRuntime().totalMemory()
: Gibt nur JVM-Speicher zurückActivityManager.getMemoryInfo()
,Process.getFreeMemory()
Und alles , was basierend auf/proc/meminfo
- Renditen Speicher Informationen über alle Prozesse kombiniert (zB android_util_Process.cpp )Debug.getNativeHeapAllocatedSize()
- Verwendet,mallinfo()
die nur Informationen über Speicherzuweisungen zurückgeben, die vonmalloc()
und verwandten Funktionen ausgeführt werden (siehe android_os_Debug.cpp ).Debug.getMemoryInfo()
- macht den Job, aber es ist zu langsam. Auf dem Nexus 6 dauert ein einzelner Anruf etwa 200 ms . Der Leistungsaufwand macht diese Funktion für uns nutzlos, da wir sie regelmäßig aufrufen und jeder Aufruf ziemlich auffällig ist (siehe android_os_Debug.cpp ).ActivityManager.getProcessMemoryInfo(int[])
- ruftDebug.getMemoryInfo()
intern auf (siehe ActivityManagerService.java )Schließlich haben wir den folgenden Code verwendet:
Es gibt die VmRSS- Metrik zurück. Weitere Details dazu finden Sie hier: eins , zwei und drei .
PS Ich habe festgestellt, dass dem Thema immer noch ein tatsächlicher und einfacher Codeausschnitt fehlt, wie die private Speichernutzung des Prozesses geschätzt werden kann, wenn die Leistung keine kritische Anforderung ist:
quelle
In Android Studio 3.0 haben sie den Android-Profiler eingeführt, um Ihnen zu helfen, zu verstehen, wie Ihre App CPU-, Speicher-, Netzwerk- und Batterieressourcen verwendet.
https://developer.android.com/studio/profile/android-profiler
quelle
Es gibt viele Antworten oben, die Ihnen definitiv helfen werden, aber (nach 2 Tagen des Erschwingens und Nachforschens über ADB-Speicher-Tools) denke ich, dass ich auch mit meiner Meinung helfen kann .
Wie Hackbod sagt: Wenn Sie also den gesamten physischen RAM verwenden würden, der tatsächlich jedem Prozess zugeordnet ist, und alle Prozesse addieren würden, würden Sie wahrscheinlich eine Zahl erhalten, die viel größer ist als der tatsächliche Gesamtspeicher. Es gibt also keine Möglichkeit, die genaue Speichermenge pro Prozess abzurufen.
Aber Sie können sich dem durch eine Logik nähern ... und ich werde sagen, wie ...
Zunächst müssen Sie also ein Root-Benutzer sein, damit es funktioniert. Holen Sie sich in die Konsole mit Root-Rechten, indem Sie
su
in Prozess ausführen und seine erhaltenoutput and input stream
. Dann passierenid\n
(Enter) in ouputstream und schreiben Sie es auf Prozessausgang wird Wenn bekommen einen Inputstream enthältuid=0
, sind Sie Root - Benutzer.Hier ist die Logik, die Sie im obigen Prozess verwenden werden
Wenn Sie ouputstream des Prozessdurchlaufs erhalten, befehlen Sie (procrank, dumpsys meminfo etc ...)
\n
anstelle von id und erhalten Sie seineinputstream
und lesen Sie, speichern Sie den Stream in Bytes [], char [] etc .. verwenden Sie Rohdaten..und Sie sind fertig!!!!!Genehmigung :
Überprüfen Sie, ob Sie Root-Benutzer sind:
Führen Sie Ihren Befehl mit aus
su
logcat:
Dies ist nur ein Versuch, bitte schlagen Sie mir vor, wenn ich etwas verpasst habe
quelle