wake-up-neo.com

Was ist die maximale Menge von RAM eine App verwenden kann?

Ich bin sehr gespannt auf diese Frage zum Speichermanagement des Betriebssystems Android und hoffe auf eine recht ausführliche Antwort darauf Thema.

Was ich gerne wissen würde:

  • Was ist die maximale Speichermenge (in Megabyte /as Prozentsatz des gesamten Arbeitsspeichers), den eine Android -Anwendung (die keine System-App ist) verwenden kann?
  • Gibt es Unterschiede zwischen Android-Versionen ?
  • Gibt es Unterschiede bezüglich des Herstellers des Geräts?

Und am wichtigsten:

  • Was ist/, wovon hängt es ab , wenn es um die System ermittelt, wie viel RAM eine App zur Laufzeit verwenden kann (unter der Annahme, dass das Speichermaximum pro App keine statische Zahl ist)?

Was ich bisher gehört habe (bis 2013):

  • Frühe Android Geräte hatten eine Obergrenze von 16 MB pro App
  • Später erhöhte sich diese Grenze auf 24 MB oder 32 MB

Was mich sehr neugierig macht:

Beide Grenzwerte sind sehr niedrig.

Ich habe vor kurzem den Android Task Manager heruntergeladen, um den RAM meines Geräts zu überprüfen. Was ich bemerkt habe, ist, dass es Anwendungen gibt, die ungefähr 40-50 Megabyte RAM verwenden, was offensichtlich mehr ist als die angegebene maximale RAM Auslastung von sagen wir 32 MB. Wie bestimmt Android, wie viel RAM eine App verwenden kann? Wie ist es möglich, dass Apps diese Grenze überschreiten?

Weiterhin ist mir aufgefallen, dass einige meiner Apps mit einer OutOfMemoryException abstürzen (vom System getötet?), Wenn ca. 30-40 Megabyte verwendet werden. Andererseits werden auf meinem Telefon Apps mit 100 MB und mehr nach einiger Zeit (wahrscheinlich aufgrund von Speicherverlusten) ausgeführt, die nicht abstürzen oder getötet werden. Also hängt es natürlich auch von der App selbst ab , wie viel RAM eingespart werden kann. Wie ist das möglich? (Ich habe meine Tests mit einem HTC One S mit 768 MB RAM durchgeführt)

Haftungsausschluss: Ich bin in keiner Weise mit der Android Task Manager-App verbunden.

135
Philipp Jahoda

Wie viel Arbeitsspeicher (in Megabyte/als Prozentsatz des gesamten Arbeitsspeichers) kann eine Anwendung Android (die keine System-App ist) maximal verwenden?

Das variiert je nach Gerät. getMemoryClass() on ActivityManager gibt den Wert für das Gerät an, auf dem Ihr Code ausgeführt wird.

Gibt es Unterschiede zwischen den Versionen Android?

Ja, sofern die Anforderungen an das Betriebssystem im Laufe der Jahre gestiegen sind und die Geräte angepasst werden müssen.

Gibt es Unterschiede bezüglich des Geräteherstellers?

Ja, sofern Hersteller Geräte herstellen und die Größe je nach Gerät variiert.

Welche "Nebenfaktoren" werden berücksichtigt, um zu bestimmen, wie viel RAM eine App verwenden kann?

Ich habe keine Ahnung, was "Nebenfaktoren" bedeuten.

Frühe Geräte hatten eine Obergrenze von 16 MB pro App. Spätere Geräte erhöhten diesen Wert auf 24 MB oder 32 MB

Das ist ungefähr richtig. Die Bildschirmauflösung ist eine wichtige Determinante, da größere Auflösungen größere Bitmaps bedeuten und Tablets und hochauflösende Telefone daher tendenziell noch höhere Werte aufweisen. Sie werden beispielsweise Geräte mit 48 MB Heap sehen, und es würde mich nicht wundern, wenn es Werte gibt, die darüber liegen.

Wie ist es möglich, dass Apps diese Grenze überschreiten?

Sie gehen davon aus, dass der Autor dieser App weiß, was er tut. In Anbetracht dessen, dass die Speichernutzung einer App ist für einen Core-Techniker Android schwer zu bestimmen , würde ich nicht davon ausgehen, dass die betreffende App notwendigerweise besonders genaue Ergebnisse liefert.

Der native Code (NDK) unterliegt jedoch nicht dem Heap-Limit. Und seit Android 3.0 können Apps einen "großen Heap" anfordern, normalerweise im Bereich von Hunderten von MB, aber das wird für die meisten Apps als schlechte Form angesehen.

Außerdem ist mir aufgefallen, dass einige meiner Apps mit einer OutOfMemoryException abstürzen, wenn sie etwa 30-40 Megabyte verwenden.

Denken Sie daran, dass der Android - Abfallsammler kein komprimierender Abfallsammler ist. Die Ausnahme sollte eigentlich CouldNotFindSufficientlyLargeBlockOfMemoryException sein, aber das wurde wahrscheinlich als zu wortreich angesehen. OutOfMemoryException bedeutet, dass Sie Ihren angeforderten Block nicht zuordnen konnten , nicht, dass Sie Ihren Haufen vollständig erschöpft haben.

116
CommonsWare

Es ist Ende 2018, also haben sich die Dinge geändert.

Zuallererst: starte deine App und öffne die Registerkarte Android= Profiler in Android= Studio. Du wirst sehen, wie viel Speicher es verbraucht, du wirst überrascht sein, aber es kann viel RAM zuweisen.

Auch hier ist ein großartiger Artikel in offiziellen Dokumenten mit detaillierten Anweisungen zur Verwendung von Memory Profiler, die Ihnen einen detaillierten Einblick in Ihre Speicherverwaltung geben können.

In den meisten Fällen reicht Ihnen jedoch Ihr regulärer Android Profiler).

enter image description here

Normalerweise startet eine App mit 50 MB RAM Zuweisung, springt aber sofort auf 90 MB, wenn Sie anfangen, einige Fotos in den Speicher zu laden. Wenn Sie Activity mit einem ViewPager mit vorinstallierten Fotos öffnen (jeweils 3,5 MB) Sie können 190 MB leicht in Sekunden erhalten.

Dies bedeutet jedoch nicht, dass Sie Probleme mit der Speicherverwaltung haben.

Der beste Rat, den ich geben kann, ist, die Richtlinien und Best Practices zu befolgen, die besten Bibliotheken zum Laden von Bildern zu verwenden (Glide, Picasso), und alles wird gut.


Wenn Sie jedoch etwas anpassen müssen und wirklich wissen müssen, wie viel Speicher Sie manuell zuweisen können, können Sie den gesamten freien Speicher abrufen und einen vorher festgelegten Anteil (in%) daraus berechnen. In meinem Fall musste ich entschlüsselte Fotos im Speicher zwischenspeichern, damit ich sie nicht jedes Mal entschlüsseln muss, wenn der Benutzer durch die Liste gleitet.

Zu diesem Zweck können Sie die gebrauchsfertige LruCache-Klasse verwenden. Es ist eine Cache-Klasse, die automatisch nachverfolgt, wie viel Speicher Ihre Objekte zuordnen (oder wie viele Instanzen), und die ältesten entfernt, um die jüngsten anhand ihres Nutzungsverlaufs zu erfassen. Hier ist ein großartiges Tutorial, wie man es benutzt.

In meinem Fall habe ich zwei Instanzen von Caches erstellt: für Thumbs und Attachments. Sie wurden mit Singleton-Zugriff statisch gemacht, sodass sie global in der gesamten App verfügbar sind.

cache-Klasse:

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}


@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

So berechne ich kostenlos verfügbar RAM und wie viel ich daraus beissen kann:

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

Und so verwende ich es in Adaptern, um ein zwischengespeichertes Bild zu erhalten:

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

und wie ich es im Hintergrund-Thread in den Cache gestellt habe (reguläre AsyncTask):

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

Meine App zielt auf API 19+ ab, sodass Geräte nicht alt sind und diese Teile der verfügbaren RAM sind in meinem Fall gut genug für den Cache (1% und 3%).

Fun fact: Android hat keine APIs oder andere Hacks zu bekommen Die Menge an Speicher, die Ihrer App zugewiesen wurde, wird basierend auf verschiedenen Faktoren im Handumdrehen berechnet.


P.S. Ich verwende ein statisches Klassenfeld, um einen Cache zu speichern, aber gemäß den neuesten Android Richtlinien wird empfohlen, ViewModel-Architekturkomponente für diesen Zweck zu verwenden.

13
Kirill Karmazin

Die Speicherbeschränkungen pro App sind hier abhängig von der Bildschirmgröße und Android= Version: https://drive.google.com/file/d/0B7Vx1OvzrLa3Y0R0X1BZbUpicGc/view?usp=sharing =

Quelle: Android Compatibility Downloads http://source.Android.com/compatibility/downloads.html ; Kompatibilitätsdefinitionsdokument (CDD), Abschnitt Kompatibilität oder Laufzeit der virtuellen Maschine Kompatibilität

12
user5554029