ios app maximales Speicherbudget

152

Ich arbeite an einem iOS-Spiel, das mindestens auf die 3gs abzielt. Wir verwenden HD-Assets für Retina-Anzeigegeräte (iPhone 4, iPod Touch 4. Generation).

In Bezug auf den Speicher scheint der Ipod Touch der 4. Generation für uns das Gerät mit den meisten Einschränkungen zu sein, da er über dieselbe RAM-Größe (256 im Vergleich zu 512 von Iphone 4) wie 3gs verfügt, wir jedoch HD-Assets verwenden. Die App stürzte früher ab, als versucht wurde, 100-110 MB RAM zu laden, aber jetzt, da wir nur noch 70 MB haben, hatten wir noch nie einen Absturz beim Laden.

Nach langem Suchen scheint es keine offizielle Grenze zu geben. Wie sollten wir also vorgehen, um zu wissen, welches Speicherbudget wir verwenden müssen, um sicher zu sein? Wir möchten den Künstlern ein Budget geben können, das sie ohne Speicherprobleme für jede Karte verwenden können.

frilla
quelle
14
Ich bin mir nicht sicher, wie diese Frage ein Duplikat von etwas sein kann, das zu einem späteren Zeitpunkt gestellt wurde.
Jasper

Antworten:

42

Ich denke, Sie haben Ihre eigene Frage beantwortet: Versuchen Sie, die 70-MB-Grenze nicht zu überschreiten, aber es hängt wirklich von vielen Dingen ab: Welche iOS-Version Sie verwenden (nicht SDK), wie viele Anwendungen im Hintergrund ausgeführt werden, welcher genaue Speicher Sie verwenden usw.

Vermeiden Sie einfach die sofortigen Speicherspritzer (z. B. verwenden Sie 40 MB RAM und weisen dann 80 MB mehr für eine kurze Berechnung zu). In diesem Fall würde iOS Ihre Anwendung sofort beenden.

Sie sollten auch das verzögerte Laden von Assets in Betracht ziehen (laden Sie sie nur, wenn Sie sie wirklich benötigen und nicht vorher).

Max
quelle
2
Es ist nur so, dass wir so viel Zeug wie möglich einbauen wollten (Grafik & Sound). Künstler werden immer so viel wie möglich in ein Spiel stecken wollen, deshalb möchte ich sie mit einem Budget begrenzen. Ich denke, wir müssen nur auf vielen verschiedenen Geräten in verschiedenen Einstellungen testen, um einen angemessenen maximalen Speicherbedarf zu finden.
Frilla
2
Wird nur 70MB Zuweisung (die vermutlich unter dem Budget) zu jeder Zeit auf dem Gerät (auch nach intensiver Nutzung in anderen speicherhungrigen Anwendungen) immer eine erfolgreiche Zuordnung gewährleisten, oder wird es möglicherweise noch abstürzen?
Steven Lu
1
@Steven Lu es hängt von deinem Gerät ab. ZB bei neueren wie iPhone5 oder iPad4 ist die Zuweisung von 70 MB überhaupt kein Problem.
Max
1
Ja, aber ich möchte wissen, ob ich sicher sein kann, dass meine App nicht beendet wird, solange ich die Gesamtnutzung unter dem magischen gerätespezifischen Speicherbudget halte!
Steven Lu
1
Es gibt keine Garantien
Max
421

Testergebnisse mit dem Dienstprogramm Split geschrieben (Link ist in seiner Antwort):

Gerät: (Absturzmenge / Gesamtmenge / Prozentsatz der Gesamtmenge)

  • iPad1: 127 MB / 256 MB / 49%
  • iPad2: 275 MB / 512 MB / 53%
  • iPad3: 645 MB / 1024 MB / 62%
  • iPad4: 585 MB / 1024 MB / 57% (iOS 8.1)
  • iPad Mini 1. Generation: 297 MB / 512 MB / 58%
  • iPad Mini Retina: 696 MB / 1024 MB / 68% (iOS 7.1)
  • iPad Air: 697 MB / 1024 MB / 68%
  • iPad Air 2: 1383 MB / 2048 MB / 68% (iOS 10.2.1)
  • iPad Pro 9,7 ": 1395 MB / 1971 MB / 71% (iOS 10.0.2 (14A456))
  • iPad Pro 10.5 ”: 3057/4000 / 76% (iOS 11 Beta4)
  • iPad Pro 12.9 ”(2015): 3058/3999 / 76% (iOS 11.2.1)
  • iPad Pro 12.9 ”(2017): 3057/3974 / 77% (iOS 11 Beta4)
  • iPad Pro 11.0 ”(2018): 2858/3769 / 76% (iOS 12.1)
  • iPad Pro 12.9 ”(2018, 1 TB): 4598/5650 / 81% (iOS 12.1)
  • iPad 10.2: 1844/2998 / 62% (iOS 13.2.3)
  • iPod touch 4. Generation: 130 MB / 256 MB / 51% (iOS 6.1.1)
  • iPod touch 5. Generation: 286 MB / 512 MB / 56% (iOS 7.0)
  • iPhone4: 325 MB / 512 MB / 63%
  • iPhone4s: 286 MB / 512 MB / 56%
  • iPhone5: 645 MB / 1024 MB / 62%
  • iPhone5s: 646 MB / 1024 MB / 63%
  • iPhone6: 645 MB / 1024 MB / 62% (iOS 8.x)
  • iPhone6 ​​+: 645 MB / 1024 MB / 62% (iOS 8.x)
  • iPhone6s: 1396 MB / 2048 MB / 68% (iOS 9.2)
  • iPhone6s +: 1392 MB / 2048 MB / 68% (iOS 10.2.1)
  • iPhoneSE: 1395 MB / 2048 MB / 69% (iOS 9.3)
  • iPhone 7: 1395/2048 MB / 68% (iOS 10.2)
  • iPhone7 +: 2040 MB / 3072 MB / 66% (iOS 10.2.1)
  • iPhone8: 1364 / 1990MB / 70% (iOS 12.1)
  • iPhone X: 1392/2785 / 50% (iOS 11.2.1)
  • iPhone XS: 2040/3754 / 54% (iOS 12.1)
  • iPhone XS Max: 2039/3735/55% (iOS 12.1)
  • iPhone XR: 1792/2813 / 63% (iOS 12.1)
  • iPhone 11: 2068/3844 / 54% (iOS 13.1.3)
  • iPhone 11 Pro Max: 2067/3740 / 55% (iOS 13.2.3)
Jaspis
quelle
2
iPhone4: ähnlicher Wert bestätigt, scheint legitim: P
cprcrack
3
Das iPhone 5 stürzt bei ± 645 MB ab.
asp_net
4
@JasperPol Ich habe Ihren Beitrag so bearbeitet, dass er verschiedene Geräte enthält, die ich habe. Ich hoffe, das ist in Ordnung. Ich habe die iOS-Version hinzugefügt, auf der ich getestet habe, falls es darauf ankommt, aber Sie können sie jederzeit entfernen, wenn Sie der Meinung sind, dass dies nicht wichtig ist.
JosephH
2
Super, dass diese Liste erstellt und gepflegt wurde. Nach meiner Erfahrung musste ich das Gedächtnis viel niedriger halten, um sicher zu gehen, vielleicht 20% von dem, was hier gezeigt wird. Die Unterschiede von Gerät zu Gerät sind ebenfalls sehr unterschiedlich.
user1021430
1
Ich habe dies gerade auf einem 12.9 iPad Pro ausgeführt. Speicherwarnung bei 2451 MB, Absturz bei 3064 MB, insgesamt 3981 MB.
Sperre
134

Ich habe ein kleines Dienstprogramm erstellt, das versucht, so viel Speicher wie möglich für den Absturz zuzuweisen, und das aufzeichnet, wann Speicherwarnungen und Abstürze aufgetreten sind. Auf diese Weise können Sie herausfinden, wie hoch das Speicherbudget für jedes iOS-Gerät ist.

https://github.com/Split82/iOSMemoryBudgetTest

Teilt
quelle
Ich habe einen interessanten Test durchgeführt: Ich habe meine App mit Xcode-Überwachung ausgeführt, den Hintergrund eingegeben und den BudgetTest ausgeführt. Der Test wurde beendet, während meine In-Background-App dies nicht tat. Ich bin daran interessiert zu wissen warum. Dies widerspricht auch dem, was @cprcrack in der anderen Antwort gesagt hat.
Roberto
19

In meiner App ist die Benutzererfahrung besser, wenn mehr Speicher verwendet wird. Daher muss ich mich entscheiden, ob ich wirklich den gesamten Speicher freigeben soll, in dem ich arbeiten kann didReceiveMemoryWarning. Basierend auf der Antwort von Split und Jasper Pol scheint die Verwendung von maximal 45% des gesamten Gerätespeichers ein sicherer Schwellenwert zu sein (danke Jungs).

Für den Fall, dass sich jemand meine tatsächliche Implementierung ansehen möchte:

#import "mach/mach.h"

- (void)didReceiveMemoryWarning
{
    // Remember to call super
    [super didReceiveMemoryWarning];

    // If we are using more than 45% of the memory, free even important resources,
    // because the app might be killed by the OS if we don't
    if ([self __getMemoryUsedPer1] > 0.45)
    {
        // Free important resources here
    }

    // Free regular unimportant resources always here
}

- (float)__getMemoryUsedPer1
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kerr == KERN_SUCCESS)
    {
        float used_bytes = info.resident_size;
        float total_bytes = [NSProcessInfo processInfo].physicalMemory;
        //NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
        return used_bytes / total_bytes;
    }
    return 1;
}

Swift (basierend auf dieser Antwort ):

func __getMemoryUsedPer1() -> Float
{
    let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
    let name = mach_task_self_
    let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
    var size = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
    var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)
    let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
    let info = infoPointer.move()
    infoPointer.dealloc(1)
    if kerr == KERN_SUCCESS
    {
        var used_bytes: Float = Float(info.resident_size)
        var total_bytes: Float = Float(NSProcessInfo.processInfo().physicalMemory)
        println("Used: \(used_bytes / 1024.0 / 1024.0) MB out of \(total_bytes / 1024.0 / 1024.0) MB (\(used_bytes * 100.0 / total_bytes)%%)")
        return used_bytes / total_bytes
    }
    return 1
}
cprcrack
quelle
1
Größe sollte TASK_BASIC_INFO_COUNT anstelle von sizeof (info) sein - dieser Fehler wurde an vielen Stellen mit demselben Code
kopiert
Danke Speakus. Sie scheinen aufgrund dieses Links Recht zu haben . Haben Sie eine andere Referenz, in der diese Informationen zu finden sind?
cprcrack
Apple verwendet TASK_BASIC_INFO_COUNT zu
Maxim Kholyavkin
45% ist kein sicheres Limit mehr, es liegt zu nahe an 50% Absturzwert für iPhone X. Ich empfehle die Verwendung von 40% oder einen separaten Wert für jedes Gerät.
Slyv
8

Durch das Verzweigen des SPLITS-Repos habe ich eines erstellt, um den iOS-Speicher zu testen, der der heutigen Erweiterung zugewiesen werden kann

iOSMemoryBudgetTestForExtension

Das Folgende ist das Ergebnis, das ich in iPhone 5s bekommen habe

Speicherwarnung bei 10 MB

App bei 12 MB abgestürzt

Auf diese Weise lässt Apple lediglich zu, dass Erweiterungen ihr volles Potenzial entfalten .

Hart
quelle
7

Sie sollten Sitzung 147 aus den Videos der WWDC 2010-Sitzung ansehen . Es handelt sich um "Erweiterte Leistungsoptimierung unter iPhone OS, Teil 2".
Es gibt viele gute Ratschläge zur Speicheroptimierung.

Einige der Tipps sind:

  • Verwenden Sie verschachtelte NSAutoReleasePools, um sicherzustellen, dass Ihre Speichernutzung nicht ansteigt.
  • Verwenden Sie diese CGImageSourceOption, wenn Sie Miniaturansichten aus großen Bildern erstellen.
  • Reagieren Sie auf Warnungen zu wenig Speicher.
Kobski
quelle
Bei meiner Frage geht es nicht darum, wie man optimiert (danke für den Link), sondern darum, wie viel wir uns erlauben können, zu nutzen. Der Grund dafür ist, dass Künstler, wenn wir beispielsweise auf 20 MB optimieren, diese 20 MB verwenden möchten, wenn sie innerhalb des angemessenen "Budgets" liegen, auch bekannt als sicher, dass dies keine Leistungsprobleme oder Speicherabstürze verursacht.
Frilla
OK. Der Absturz ist darauf zurückzuführen, dass das Betriebssystem die App aufgrund des eingeschränkten Speichers beendet. Sie können einfach ein NSLogInside hinzufügen didReceiveMemoryWarningund dann einige Tests durchführen, bei denen Sie unterschiedliche Speichermengen zuweisen und dann sehen, wann die Speicherwarnungen beginnen.
Kobski
4

Ab iOS13 gibt es eine von Apple unterstützte Möglichkeit, dies mithilfe von abzufragen

#include <os/proc.h>

size_t os_proc_available_memory(void)

Hier vorgestellt: https://developer.apple.com/videos/play/wwdc2019/606/

Etwa min 29-ish.

Bearbeiten: Hinzufügen eines Links zur Dokumentation https://developer.apple.com/documentation/os/3191911-os_proc_available_memory?language=objc

Exaberri Tokugawa
quelle
Schließlich! Ich habe os_proc_available_memory () auf wenigen Geräten getestet und die Ergebnisse sind den Werten in der großen Tabelle oben sehr ähnlich!
Slyv
3
- (float)__getMemoryUsedPer1
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO;
    kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kerr == KERN_SUCCESS)
    {
        float used_bytes = info.resident_size;
        float total_bytes = [NSProcessInfo processInfo].physicalMemory;
        //NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
        return used_bytes / total_bytes;
    }
    return 1;
}

Wenn Sie TASK_BASIC_INFO_COUNT anstelle von MACH_TASK_BASIC_INFO verwenden, erhalten Sie

kerr == KERN_INVALID_ARGUMENT (4)

Dmitry Preobrazhenskiy
quelle
Sie sollten zumindest erwähnen, dass Ihre Antwort fast ein genaues Kopieren und Einfügen von @ cprcrack's oben ist. Der einzige Unterschied ist TASK_BASIC_INFO_COUNT.
Mrvincenzo
2

Ich habe eine weitere Liste erstellt, indem ich die Jaspers-Liste nach dem RAM des Geräts sortiert habe (ich habe meine eigenen Tests mit dem Split-Tool durchgeführt und einige Ergebnisse korrigiert - überprüfen Sie meine Kommentare im Jaspers-Thread).

Geräte-RAM: Prozentbereich zum Absturz

  • 256 MB: 49% - 51%
  • 512 MB: 53% - 63%
  • 1024 MB: 57% - 68%
  • 2048 MB: 68% - 69%
  • 3072 MB: 63% - 66%
  • 4096 MB: 77%
  • 6144 MB: 81%

Spezialfälle:

  • iPhone X (3072 MB): 50%
  • iPhone XS / XS Max (4096 MB): 55%
  • iPhone XR (3072 MB): 63%
  • iPhone 11/11 Pro Max (4096 MB): 54% - 55%

Geräte-RAM kann leicht gelesen werden:

[NSProcessInfo processInfo].physicalMemory

Nach meiner Erfahrung ist es sicher, 45% für 1-GB-Geräte, 50% für 2/3-GB-Geräte und 55% für 4-GB-Geräte zu verwenden. Prozent für macOS können etwas größer sein.

Slyv
quelle
Update: Es scheint, dass das iPhone X eine Ausnahme darstellt - es stürzt ab, wenn 50% des Arbeitsspeichers verwendet werden (getestet mit der iOSMemoryBudgetTest-App). Ich habe die Liste aktualisiert.
Slyv
0

Mit den vielen Antworten oben habe ich die neue Methode von Apples os_proc_available_memory()für iOS 13+ implementiert, NSByteCountFormatterdie eine Reihe nützlicher Formatierungsoptionen für eine bessere Ausgabe des Speichers bietet:

#include <os/proc.h>

....

- (NSString *)memoryStringForBytes:(unsigned long long)memoryBytes {
    NSByteCountFormatter *byteFormatter = [[NSByteCountFormatter alloc] init];
    byteFormatter.allowedUnits = NSByteCountFormatterUseGB;
    byteFormatter.countStyle = NSByteCountFormatterCountStyleMemory;
    NSString *memoryString = [byteFormatter stringFromByteCount:memoryBytes];
    return memoryString;
}

- (void)memoryLoggingOutput {
    if (@available(iOS 13.0, *)) {
        NSLog(@"Physical memory available: %@", [self memoryStringForBytes:[NSProcessInfo processInfo].physicalMemory]);
        NSLog(@"Memory A (brackets): %@", [self memoryStringForBytes:(long)os_proc_available_memory()]);
        NSLog(@"Memory B (no brackets): %@", [self memoryStringForBytes:(long)os_proc_available_memory]);
    }
}

Wichtiger Hinweis: Vergessen Sie das ()am Ende nicht. Ich habe beide NSLogOptionen in die memoryLoggingOutputMethode aufgenommen, da Sie nicht gewarnt werden, dass sie fehlen, und wenn die Klammern nicht eingeschlossen werden, wird ein unerwartetes, aber konstantes Ergebnis zurückgegeben.

Die von der Methode zurückgegebene Zeichenfolge memoryStringForBytesgibt folgende Werte aus:

NSLog(@"%@", [self memoryStringForBytes:(long)os_proc_available_memory()]); // 1.93 GB
// 2 seconds later
NSLog(@"%@", [self memoryStringForBytes:(long)os_proc_available_memory()]); // 1.84 GB
App Dev Guy
quelle