wake-up-neo.com

Ermitteln Sie die Größe des Anwendungs-Heapspeichers in Android

Wie erkennt man programmgesteuert die Größe des Anwendungs-Heapspeichers, der für eine Android App verfügbar ist?

Ich habe gehört, dass es eine Funktion gibt, die dies in späteren Versionen des SDK ausführt. Auf jeden Fall suche ich nach einer Lösung, die ab 1.5 funktioniert.

142
hpique

Es gibt zwei Möglichkeiten, über Ihre Formulierung "verfügbare Größe des Anwendungsheapspeichers" nachzudenken:

  1. Wie viel Heap kann meine App verwenden, bevor ein schwerer Fehler ausgelöst wird? Und

  2. Wie viel Heap sollte meine App verwenden, angesichts der Einschränkungen der Betriebssystemversion Android und der Hardware des Geräts des Benutzers?

Es gibt für jedes der oben genannten Verfahren eine andere Methode.

Für Punkt 1 oben: maxMemory()

dies kann wie folgt aufgerufen werden (z. B. in der Methode onCreate() Ihrer Hauptaktivität):

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

Diese Methode gibt an, wie viel Byte Heap Ihre App insgesamt erlaubt verwenden darf.

Für Punkt 2 oben: getMemoryClass()

was wie folgt aufgerufen werden kann:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

Diese Methode gibt ungefähr an, wie viele Megabyte Heap Ihrer App sollte verwendet werden, wenn die Grenzen des aktuellen Geräts und die Rechte anderer Apps ordnungsgemäß beachtet werden sollen um zu rennen, ohne wiederholt in den onStop()/onResume() - Zyklus gezwungen zu werden, da sie grob aus dem Speicher gelöscht werden, während Ihre Elefanten-App im Android Whirlpool ein Bad nimmt.

Diese Unterscheidung ist meines Wissens nicht eindeutig dokumentiert, aber ich habe diese Hypothese auf fünf verschiedenen Android Geräten (siehe unten) getestet und zu meiner eigenen Zufriedenheit bestätigt, dass dies eine korrekte Interpretation ist.

Bei einer Standardversion von Android gibt maxMemory() in der Regel ungefähr die gleiche Anzahl von Megabyte zurück, wie in getMemoryClass() angegeben (d. H. Ungefähr das Millionenfache des letztgenannten Werts).

Die einzige Situation (von der ich weiß), für die die beiden Methoden abweichen können, ist auf einem gerooteten Gerät, auf dem eine Android - Version wie CyanogenMod ausgeführt wird, mit der der Benutzer manuell auswählen wie groß auswählen kann Für jede App sollte eine Heap-Größe zulässig sein. In CM wird diese Option beispielsweise unter "CyanogenMod-Einstellungen"/"Leistung"/"VM-Heap-Größe" angezeigt.

HINWEIS: BEACHTEN SIE, DASS DAS MANUELLE EINSTELLEN DIESES WERTES IHR SYSTEM BEEINTRÄCHTIGEN KANN, INSBESONDERE, wenn Sie einen kleineren Wert als den für Ihr Gerät normalen auswählen.

Hier sind meine Testergebnisse, die die von maxMemory() und getMemoryClass() zurückgegebenen Werte für vier verschiedene Geräte zeigen, auf denen CyanogenMod ausgeführt wird, wobei jeweils zwei verschiedene (manuell festgelegte) Heap-Werte verwendet werden:

  • G1:
    • Wenn VM Heap Size auf 16 MB eingestellt ist:
      • maxMemory: 16777216
      • getMemoryClass: 16
    • Wenn VM Heap Size auf 24 MB eingestellt ist:
      • maxMemory: 25165824
      • getMemoryClass: 16
  • Moto Droid:
    • Wenn VM Heap Size auf 24 MB eingestellt ist:
      • maxMemory: 25165824
      • getMemoryClass: 24
    • Wenn VM Heap Size auf 16 MB eingestellt ist:
      • maxMemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • Mit VM Heap-Größe auf 32 MB eingestellt:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • Mit VM Heap-Größe auf 24 MB festgelegt:
      • maxMemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTab:
    • Wenn VM Heap Size auf 32 eingestellt ist:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • Wenn VM Heap Size auf 64 eingestellt ist:
      • maxMemory: 67108864
      • getMemoryClass: 32

Darüber hinaus habe ich ein Novo7 Paladin-Tablet mit Ice Cream Sandwich getestet. Dies war im Wesentlichen eine Standardversion von ICS, mit der Ausnahme, dass ich das Tablet durch einen einfachen Prozess verwurzelt habe, der nicht das gesamte Betriebssystem ersetzt und insbesondere keine Schnittstelle bietet, über die die Größe des Heapspeichers manuell angepasst werden kann.

Hier sind die Ergebnisse für dieses Gerät:

  • Novo7
    • maxMemory: 62914560
    • getMemoryClass: 60

Auch (per Kishore in einem Kommentar unten):

  • HTC ein x
    • maxMemory: 67108864
    • getMemoryClass: 64

Und (per Akauppis Kommentar):

  • Samsung Galaxy Core Plus
    • maxMemory: (im Kommentar nicht angegeben)
    • getMemoryClass: 48
    • largeMemoryClass: 128

Ein Kommentar von cmcromance:

  • Galaxy S3 (Jelly Bean) großer Haufen
    • maxMemory: 268435456
    • getMemoryClass: 64

Und (pro Tencent's Kommentare):

  • LG Nexus 5 (4.4.3) normal
    • maxMemory: 201326592
    • getMemoryClass: 192
  • LG Nexus 5 (4.4.3) großer Haufen
    • maxMemory: 536870912
    • getMemoryClass: 192
  • Galaxy Nexus (4.3) normal
    • maxMemory: 100663296
    • getMemoryClass: 96
  • Galaxy Nexus (4.3) großer Haufen
    • maxMemory: 268435456
    • getMemoryClass: 96
  • Galaxy S4 Play Store Edition (4.4.2) normal
    • maxMemory: 201326592
    • getMemoryClass: 192
  • Galaxy S4 Play Store Edition (4.4.2) großer Haufen
    • maxMemory: 536870912
    • getMemoryClass: 192

Andere Geräte

  • Huawei Nexus 6P (6.0.1) normal
    • maxMemory: 201326592
    • getMemoryClass: 192

Ich habe diese beiden Methoden nicht mit dem speziellen Android getestet: largeHeap = "true" Manifest-Option seit Honeycomb, aber dank cmcromance und tencent haben wir einige Beispiele für largeHeap-Werte, wie oben angegeben.

Mein Erwartung (was von den obigen largeHeap-Zahlen unterstützt zu werden scheint) würde bedeuten, dass diese Option einen ähnlichen Effekt hat wie das manuelle Setzen des Heaps über ein Root-Betriebssystem - dh es würde den Wert von maxMemory(), während getMemoryClass() in Ruhe gelassen wird. Es gibt eine andere Methode, getLargeMemoryClass (), die angibt, wie viel Speicher für eine App mit der Einstellung largeHeap zulässig ist. In der Dokumentation für getLargeMemoryClass () heißt es: "Die meisten Anwendungen sollten nicht so viel Arbeitsspeicher benötigen und stattdessen das Limit für getMemoryClass () einhalten."

Wenn ich richtig geraten habe, hat die Verwendung dieser Option dieselben Vorteile (und Risiken) wie die Verwendung des Speicherplatzes, der von einem Benutzer bereitgestellt wird, der den Heap über ein Root-Betriebssystem aufgerüstet hat (dh, wenn Ihre App den zusätzlichen Speicher verwendet, Es wird wahrscheinlich nicht so gut mit allen anderen Apps funktionieren, die der Benutzer gleichzeitig ausführt.

Beachten Sie, dass die Speicherklasse anscheinend kein Vielfaches von 8 MB sein muss.

Aus dem Obigen können wir ersehen, dass das Ergebnis getMemoryClass() für eine bestimmte Geräte-/Betriebssystemkonfiguration unverändert ist, während sich der Wert von maxMemory () ändert, wenn der Heap vom Benutzer anders festgelegt wird.

Meine eigene praktische Erfahrung ist, dass ich auf dem G1 (der eine Speicherklasse von 16 hat), wenn ich manuell 24 MB als Heap-Größe auswähle, fehlerfrei laufen kann, selbst wenn meine Speichernutzung auf 20 MB ansteigen darf (vermutlich könnte dies der Fall sein) gehen Sie so hoch wie 24 MB, obwohl ich dies nicht ausprobiert habe). Andere ähnlich große Apps werden jedoch möglicherweise aufgrund der Schweinerei meiner eigenen App aus dem Speicher gelöscht. Und umgekehrt wird my möglicherweise aus dem Speicher gelöscht, wenn diese anderen wartungsintensiven Apps vom Benutzer in den Vordergrund gestellt werden.

Sie können also die mit maxMemory() festgelegte Speichermenge nicht überschreiten. Und Sie sollten versuchen innerhalb der durch getMemoryClass() festgelegten Grenzen bleiben. Wenn alles andere fehlschlägt, besteht eine Möglichkeit darin, die Funktionalität solcher Geräte so einzuschränken, dass Speicherplatz gespart wird.

Wenn Sie vorhaben, die in getMemoryClass() angegebene Anzahl von Megabyte zu überschreiten, empfehle ich, lange und intensiv an dem Speichern und Wiederherstellen des Status Ihrer App zu arbeiten, damit die Benutzererfahrung in diesem Fall praktisch ununterbrochen bleibt Es tritt ein onStop()/onResume() - Zyklus auf.

In meinem Fall beschränke ich meine App aus Gründen der Leistung auf Geräte mit Version 2.2 und höher. Das bedeutet, dass fast alle Geräte, auf denen meine App ausgeführt wird, eine Speicherklasse von 24 oder höher haben. So kann ich entwerfen, bis zu 20 MB Heap zu belegen, und bin ziemlich zuversichtlich, dass meine App mit den anderen Apps, die der Benutzer möglicherweise gleichzeitig ausführt, gut funktioniert.

Es wird jedoch immer einige Root-Benutzer geben, die eine Version 2.2 oder höher von Android auf ein älteres Gerät (z. B. ein G1) geladen haben. Wenn Sie auf eine solche Konfiguration stoßen, sollten Sie Ihren Speicherverbrauch im Idealfall reduzieren, auch wenn maxMemory() Ihnen mitteilt, dass Sie viel höher gehen können als die 16 MB, die getMemoryClass() Ihnen mitteilt sollte zielen. Und wenn Sie nicht zuverlässig sicherstellen können, dass Ihre App innerhalb dieses Budgets läuft, stellen Sie sicher, dass onStop()/onResume() reibungslos funktioniert.

getMemoryClass(), wie von Diane Hackborn (hackbod) oben angegeben, ist nur ab API-Level 5 (Android 2.0) verfügbar. Sie können also davon ausgehen, dass die physische Hardware eines Geräts früher ausgeführt wird Die Version des Betriebssystems unterstützt Apps, die einen Heap-Speicherplatz von maximal 16 MB belegen, optimal.

Im Gegensatz dazu ist maxMemory() laut Dokumentation bis zur API-Ebene 1 verfügbar. maxMemory() wird in einer Version vor 2.0 wahrscheinlich einen Wert von 16 MB zurückgeben, aber ich - do sehen, dass der Benutzer in meinen (viel späteren) CyanogenMod-Versionen einen Heap-Wert von nur 12 MB auswählen kann, was vermutlich zu einer niedrigeren Heap-Grenze führen würde, und daher würde ich vorschlagen, dass Sie den Test fortsetzen maxMemory() -Wert, auch für Betriebssystemversionen vor 2.0. In dem unwahrscheinlichen Fall, dass dieser Wert noch niedriger als 16 MB ist, müssen Sie die Ausführung möglicherweise sogar ablehnen, wenn Sie mehr als maxMemory() angeben, dass dies zulässig ist.

441
Carl

Das offizielle API lautet:

Dies wurde in 2.0 eingeführt, wo größere Speichergeräte erschienen. Sie können davon ausgehen, dass Geräte, auf denen frühere Versionen des Betriebssystems ausgeführt werden, die ursprüngliche Speicherklasse (16) verwenden.

20
hackbod

Debug.getNativeHeapSize() wird den Trick machen, sollte ich denken. Es ist jedoch seit 1.0 da.

Die Klasse Debug verfügt über viele großartige Methoden zum Verfolgen von Zuordnungen und anderen Leistungsproblemen. Wenn Sie eine Situation mit wenig Arbeitsspeicher feststellen müssen, lesen Sie auch Activity.onLowMemory().

13
Neil Traft

So machst du es:

Abrufen der maximalen Heap-Größe, die die App verwenden kann:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

So ermitteln Sie, wie viel Heap Ihre App derzeit verwendet:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

Abrufen, wie viel des Heaps Ihre App jetzt verwenden kann (verfügbarer Speicher):

long availableMemory=maxMemory-usedMemory;

Und um jedes von ihnen schön zu formatieren, können Sie Folgendes verwenden:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 
13

Dies gibt die maximale Größe des Heapspeichers in Bytes zurück:

Runtime.getRuntime().maxMemory()

Ich habe ActivityManager.getMemoryClass () verwendet, aber in CyanogenMod 7 (ich habe es nicht anderswo getestet) wird ein falscher Wert zurückgegeben, wenn der Benutzer die Größe des Heapspeichers manuell festlegt.

4
fhucho

Einige Operationen sind schneller als Java Heapspeichermanager. Operationen verzögern können für einige Zeit Speicherplatz freigeben. Sie können diese Methode verwenden, um Heapgrößenfehler zu umgehen:

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {

    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {

    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    waitForGarbageCollector(
      callback);
  } else {

    // Memory resources are availavle, go to next operation:

    callback.run();
  }
}
2
Zon

Asus Nexus 7 (2013) 32Gig: getMemoryClass () = 192 maxMemory () = 201326592

Ich habe den Fehler gemacht, mein Spiel auf dem Nexus 7 als Prototyp zu erstellen, und dann festgestellt, dass auf dem generischen 4.04-Tablet meiner Frau fast sofort kein Speicher mehr verfügbar ist (Speicherklasse 48, maxmemory 50331648).

Ich muss mein Projekt neu strukturieren, um weniger Ressourcen zu laden, wenn ich feststelle, dass die Speicherklasse niedrig ist.
Gibt es in Java) eine Möglichkeit, die aktuelle Heap-Größe anzuzeigen? (Ich kann sie beim Debuggen im logCat deutlich sehen, aber ich möchte eine Möglichkeit, sie in zu sehen Code, der angepasst werden soll, beispielsweise wenn currentheap> (maxmemory/2) Bitmaps hoher Qualität entladen und niedrige Qualität laden

1
Tkraindesigns
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

wert ist b

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

wert ist MB

0
qinqie

Meinen Sie programmatisch oder nur während Sie entwickeln und debuggen? In letzterem Fall können Sie diese Informationen aus der DDMS-Perspektive in Eclipse anzeigen. Wenn Ihr Emulator (möglicherweise sogar ein angeschlossenes physisches Telefon) ausgeführt wird, werden die aktiven Prozesse in einem Fenster auf der linken Seite aufgelistet. Sie können es auswählen und es gibt eine Option, um die Heap-Zuordnungen zu verfolgen.

0
Steve Haley