Frage

Wie erkennen Sie programmatisch die Anwendung Heap-Größe zur Verfügung zu einer Android App?

Ich habe gehört, es gibt eine Funktion, die dies tut in späteren Versionen des SDK. Auf jeden Fall, ich suche für Lösung, die funktioniert für 1,5 und nach oben.

War es hilfreich?

Lösung

Es gibt zwei Möglichkeiten, um Ihre Formulierung „Anwendung Heap-Größe verfügbar“ zu denken:

  1. Wie viel Heap kann meine app Verwendung vor einem harten Fehler ausgelöst wird? Und

  2. Wie viel Heap sollte meine app Nutzung, angesichts der Zwänge der Android OS-Version und Hardware des Geräts des Benutzers?

Es gibt eine andere Methode für jede der oben genannten Bestimmung.

Für Punkt 1: maxMemory()

, die aufgerufen werden können (zum Beispiel in der Haupt onCreate() Methode Aktivität) wie folgt:

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

Diese Methode zeigt Ihnen, wie viele Gesamt Bytes Heap-App ist erlaubt verwenden.

Für Punkt 2 oben: getMemoryClass()

, die wie folgt aufgerufen werden kann:

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

Diese Methode sagt Ihnen, etwa wie viele Megabyte Heap-App sollte verwenden, wenn er will richtig unter Beachtung der Grenzen der vorliegenden Vorrichtung sein, und der Rechte von anderen Anwendungen, ohne dass immer wieder gezwungen, in den onStop() / onResume() Zyklus zu laufen, wie sie unsanft ausgespült Speicher werden während elephantine App ein Bad im Android Jacuzzi nimmt.

Diese Unterscheidung nicht klar dokumentiert ist, soweit ich weiß, aber ich diese Hypothese auf fünf verschiedenen Android-Geräte getestet habe (siehe unten) und hat zu meiner eigenen Zufriedenheit bestätigt, dass dies eine richtige Interpretation ist.

Für eine Lager-Version von Android, maxMemory() wird in der Regel zurückgeben etwa die gleiche Anzahl von Megabytes wie in getMemoryClass() angegeben sind (das heißt, etwa eine Million mal letztere Wert).

Die einzige Situation (von denen ich bin mir bewusst), für die die beiden Methoden können divergieren auf einem verwurzelten Gerät ist eine Android-Version wie CyanogenMod ausgeführt, die manuell ermöglicht es dem Benutzer wählen , wie groß ein Heap-Größe sollte für jede Anwendung zugelassen werden. In CM zum Beispiel dieser Option erscheint unter "CyanogenMod Einstellungen" / "Performance" / "VM-Heap-Größe".

. Hinweis: Beachten Sie, dass Sie diesen Wert MANUALLY CAN MESS Ihr System, vor allem, wenn Sie einen kleineren Wert wählen als normal für Ihr Gerät ist

Hier sind meine Testergebnisse die Werte zurück von maxMemory() und getMemoryClass() für vier verschiedene Geräte mit CyanogenMod zeigt, mit zwei verschiedenen (manuell gesetzt) ??Heap-Werte für jeden:

  • G1:
    • Mit VM Heap-Größe auf 16 MB:
      • MaxMemory: 16777216
      • getMemoryClass: 16
    • Mit VM Heap-Größe auf 24 MB:
      • MaxMemory: 25165824
      • getMemoryClass: 16
  • Moto Droid:
    • Mit VM Heap-Größe auf 24 MB:
      • MaxMemory: 25165824
      • getMemoryClass: 24
    • Mit VM Heap-Größe auf 16 MB:
      • MaxMemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • Mit VM Heap Größe auf 32 MB:
      • MaxMemory: 33554432
      • getMemoryClass: 32
    • Mit VM Heap Größe auf 24 MB:
      • MaxMemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTAB:
    • Mit VM Heap-Größe auf 32:
      • MaxMemory: 33554432
      • getMemoryClass: 32
    • Mit VM Heap-Größe auf 64:
      • MaxMemory: 67108864
      • getMemoryClass: 32

Zusätzlich zu dem oben testete ich auf einem Novo7 Paladin Tablet mit Ice Cream Sandwich. Dies war im Wesentlichen eine Lager-Version von ICS, außer, dass ich die Tablette durch einen einfachen Prozess verwurzelt habe, die nicht das gesamte O nicht ersetzt, und insbesondere bieten keine Schnittstelle, die die Heap-Größe manuell eingestellt werden.

Für das Gerät, hier sind die Ergebnisse:

  • Novo7
    • MaxMemory: 62914560
    • getMemoryClass: 60

Auch (pro Kishore in einem Kommentar seinniedrig):

  • HTC One X
    • MaxMemory: 67108864
    • getMemoryClass: 64

Und (pro akauppi Kommentar):

  • Samsung Galaxy Core Plus
    • MaxMemory: (Nicht in Kommentar angegeben)
    • getMemoryClass: 48
    • largeMemoryClass: 128

Per Kommentar von cmcromance:

  • Galaxy S3 (Jelly Bean) großen Haufen
    • MaxMemory: 268435456
    • getMemoryClass: 64

Und (pro Tencent Kommentare):

  • LG Nexus 5 (4.4.3) Normal
    • MaxMemory: 201326592
    • getMemoryClass: 192
  • LG Nexus 5 (4.4.3) große Haufen
    • MaxMemory: 536870912
    • getMemoryClass: 192
  • Galaxy Nexus (4.3) Normal
    • MaxMemory: 100663296
    • getMemoryClass: 96
  • Galaxy Nexus (4.3) große 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ße Haufen
    • MaxMemory: 536870912
    • getMemoryClass: 192

Andere Geräte

  • Huawei Nexus 6P (6.0.1) Normal
    • MaxMemory: 201326592
    • getMemoryClass: 192

Ich habe diese beiden Verfahren mit dem speziellen nicht getestet Android. LargeHeap = „true“ manifest Option, da Honeycomb verfügbar, aber dank cmcromance und tencent wir einige Beispiel largeHeap Werte haben, wie oben berichtet,

Mein Erwartung (die durch die largeHeap Zahlen unterstützt zu werden scheint oben) wäre, dass diese Option ähnlich auswirken würde den Heap manuell über eine verwurzelte O Einstellung - das heißt, es sei das heben Wert von maxMemory() während allein lassend getMemoryClass(). Es ist eine weitere Methode, getLargeMemoryClass (), die angibt, wie viel Speicher für eine Anwendung ist, die zulässige largeHeap Einstellung. Die Dokumentation für getLargeMemoryClass () heißt es: „die meisten Anwendungen sollte diese Menge an Speicher nicht benötigen, und sollte stattdessen mit dem getMemoryClass () Grenze bleiben.“

Wenn ich richtig erraten habe, dann diese Option die gleichen Vorteile hätte (und Gefahren) als würde mit dem Raum, der von einem Benutzer zur Verfügung gestellt, die den Heap über ein verwurzeltes O upped hat (dh wenn Ihre Anwendung verwendet die zusätzliche Speicher, wird es nicht wahrscheinlich so schön mit dem, was anderen Anwendungen spielen die Benutzer gleichzeitig ausgeführt wird).

Beachten Sie, dass die Speicherklasse anscheinend brauchen nicht ein Vielfaches von 8 MB zu sein.

Wir können aus den oben sehen, dass das getMemoryClass() Ergebnis wird für ein bestimmtes Gerät / OS-Konfiguration unveränderlich, während die MaxMemory () Wert ändert sich, wenn der Heap durch den Benutzer anders eingestellt ist.

Meine eigene praktische Erfahrung ist, dass auf dem G1 (die eine Speicherklasse von 16 hat), wenn ich manuell 24MB als Heap-Größe wählen, ich ohne erroring laufen kann, selbst wenn meine Speichernutzung zu 20MB driften gelassen wird ( vermutlich könnte es so hoch wie 24MB gehen, obwohl ich nicht versucht haben). Aber auch andere ähnlich große ish Apps können aus dem Speicher als Ergebnis meiner eigenen App pigginess gespült bekommen. Und umgekehrt mein App aus dem Speicher erhalten gespült werden, wenn diese anderen High-Wartung Anwendungen in den Vordergrund durch den Benutzer gebracht werden.

So können Sie nicht die Größe des Speichers durch maxMemory() angegeben gehen. Und sollten Sie versuchen in den Grenzen von getMemoryClass() angegeben zu bleiben. Eine Möglichkeit, das zu tun, wenn alles andere fehlschlägt, könnte für solche Geräte in einer Art und Weise zu begrenzen Funktionalität sein, dass conserves Speicher.

Schließlich, wenn Sie planen tun, um die Anzahl der Megabyte in getMemoryClass() angegeben gehen könnte, würde mein Rat lange und hart auf der Rettung zu arbeiten und die Wiederherstellung der staatlichen Ihre App, so dass die Erfahrung des Benutzers praktisch, wenn ein onStop() unterbrochen wird / onResume() Zyklus auftritt.

In meinem Fall aus Gründen der Leistung Ich Begrenzung meine App Geräte 2.2 und höher ausgeführt wird, und das bedeutet, dass fast alle Geräte meine app laufen wird ein memoryClass von 24 oder höher haben. Also ich entwerfen zu 20MB Haufen zu besetzen und ziemlich sicher sein, dass mein app schön mit den anderen Anwendungen kann der Benutzer zur gleichen Zeit ausgeführt werden.

spielen

Aber es wird immer ein paar verwurzelten Benutzer, die eine 2.2 oder höher Version von Android auf ein älteres Gerät geladen haben (zum Beispiel eines G1). Wenn Sie eine solche Konfiguration auftreten, im Idealfall sollten Sie Ihre Speichernutzung abspecken, auch wenn maxMemory() Ihnen sagt, dass Sie viel höher als die 16MB gehen kann, dass getMemoryClass() Ihnen sagt, dass Sie sollte werden Targeting . Und wenn Sie nicht zuverlässig sicherstellen, dass Ihre App innerhalb dieses Budgets leben werden, dann zumindest sicherstellen, dass onStop() / onResume() arbeitet nahtlos.

getMemoryClass(), wie Diane Hackborn (hackbod) oben angegeben, ist nur bis ins API-Ebene 5 (Android 2.0), und so, wie sie berät, können Sie davon ausgehen, dass die physische Hardware von jedem Gerät eine frühere Version des Laufens das Betriebssystem optimal Unterstützung Anwendungen ausgelegt ist, einen Heap-Speicher von nicht mehr als 16 MB belegt.

Im Gegensatz dazu maxMemory(), nach der Dokumentation verfügbar ist die ganze Weg zurück zu API-Ebene 1. maxMemory(), auf einer Pre-2.0-Version, wird wahrscheinlich einen 16MB Wert zurückgeben, aber ich tun sehen, dass in meinen (viel später) CyanogenMod Versionen der Benutzer einen Heap-Wert so niedrig wie 12MB auswählen kann, die vermutlich in einer unteren Haufen Grenze führen würde, und so würde ich vorschlagen, dass Sie auch weiterhin den maxMemory() Wert testen, auch für die Versionen von das Betriebssystem vor 2.0. Man könnte sogar in dem unwahrscheinlichen Fall laufen zu verweigern, dass dieser Wert auch als 16MB senkt gesetzt ist, wenn Sie mehr haben müssen als maxMemory() anzeigt erlaubt ist.

Andere Tipps

Die offizielle API ist:

  

Dies wurde in 2.0 eingeführt, wo größere Speichergeräte erschienen. Sie können davon ausgehen, dass die Geräte vor Versionen der OS laufen die ursprüngliche Speicherklasse verwenden (16).

Debug.getNativeHeapSize() wird es tun, sollte ich denken. Es ist dort seit 1.0, though.

Die Debug Klasse hat viele tolle Methoden für die Verfolgung von Zuweisungen und andere Leistungsprobleme. Auch, wenn Sie benötigen eine Low-Memory-Situation zu erfassen, überprüfen Activity.onLowMemory().

Hier ist, wie Sie es tun:

Ankommen der max Heap-Größe, dass die App verwenden können:

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

Ankommen, wie viel von dem Heap Ihre Anwendung derzeit verwendet:

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

Ankommen, wie viel von dem Heap Ihrer App jetzt (verfügbarer Speicher) verwenden können:

long availableMemory=maxMemory-usedMemory;

Und zu formatieren jeder von ihnen gut, können Sie:

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

Diese Erträge max Heap-Größe in Bytes:

Runtime.getRuntime().maxMemory()

Ich war mit ActivityManager.getMemoryClass (), aber auf CyanogenMod 7 (ich habe es nicht an anderer Stelle testen) es gibt einen falschen Wert, wenn die Größe Heap Benutzersätze manuell.

Einige Operationen sind schneller als Java-Heap-Speicher-Manager. Delaying Operationen für einige Zeit kann Speicherplatz freizugeben. Sie können diese Methode verwenden, um Heap-Größe Fehler zu entkommen:

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

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

machte ich den Fehler mein Spiel Prototyping auf dem Nexus 7, und dann entdecken sie liefen auf meiner Frau fast sofort von Speicher aus generic 4,04 Tablette (memoryclass 48, MaxMemory 50331648)

Ich werde mein Projekt zur Umstrukturierung benötigen weniger Ressourcen zu laden, wenn ich bestimmen memoryclass niedrig ist.
Gibt es eine Möglichkeit in Java die aktuelle Speichergröße zu sehen? (Ich kann es deutlich in der Logcat sehe beim Debuggen, aber ich würde einen Weg, wie es in dem Code zu sehen anzupassen, wie wenn currentheap> (MaxMemory / 2) Entladen hochwertige Bitmaps laden niedrige Qualität

Wollen Sie programmatisch, oder einfach nur, während Sie entwickeln und debuggen? Wenn letzteres, können Sie diese Informationen aus der DDMS Perspektive in Eclipse sehen. Wenn Ihr Emulator (möglicherweise sogar körperliche Telefon, das angeschlossen ist) ausgeführt wird, wird es die aktiven Prozesse in einem Fenster auf der linken Liste. Sie können es wählen und es gibt eine Option, um die Heapzuweisungen zu verfolgen.

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

Wert ist b

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

Wert MB

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top