budget massimo di memoria dell'app iOS


152

Sto lavorando a un gioco iOS che ha come target almeno i 3gs. Stiamo utilizzando risorse HD per dispositivi di visualizzazione retina (iPhone 4, iPod touch di quarta generazione).

Per quanto riguarda la memoria, Ipod Touch di quarta generazione sembra essere il dispositivo più vincolante per noi poiché ha la stessa quantità di RAM (256 rispetto a 512 di Iphone 4) di 3gs ma stiamo utilizzando risorse HD su di esso. L'app si arrestava in modo anomalo quando si tentava di caricare 100-110 MB di RAM, ma ora che siamo scesi a 70 MB, non abbiamo mai avuto crash di caricamento.

Dopo molte ricerche in giro, non sembra esserci alcun limite ufficiale, quindi come dovremmo sapere quale budget di memoria usare per essere sicuri? Vogliamo essere in grado di dare agli artisti un budget che possono usare senza preoccupazioni di memoria per ogni mappa.



14
Non sono sicuro di come questa domanda possa essere un duplicato di qualcosa che è stato posto in un secondo momento.
Jasper,

Risposte:


42

Penso che tu abbia risposto alla tua domanda: cerca di non andare oltre il limite di 70 Mb, tuttavia dipende davvero da molte cose: quale versione di iOS stai usando (non SDK), quante applicazioni sono in esecuzione in background, quale memoria esatta stai usando ecc.

Evita semplicemente gli spruzzi di memoria istantanea (ad esempio stai usando 40 Mb di RAM e quindi allocare 80 Mb in più per un breve calcolo). In questo caso iOS ucciderebbe immediatamente l'applicazione.

Dovresti anche considerare il caricamento pigro degli asset (caricali solo quando ne hai davvero bisogno e non in anticipo).


2
È solo che volevamo mettere quante più cose possibili (grafica e suoni). Gli artisti vorranno sempre mettere tutto il possibile in un gioco ed è per questo che voglio limitarli con un budget. Immagino che dovremo solo testare su molti dispositivi diversi con impostazioni diverse per trovare un ingombro di memoria massimo ragionevole da usare.
frilla,

2
L'allocazione di soli 70 MB (che è presumibilmente inferiore al budget) in qualsiasi momento su quel dispositivo (anche dopo un utilizzo intenso in altre app affamate di memoria) garantirà sempre un'allocazione riuscita o potrebbe comunque bloccarsi?
Steven Lu,

1
@Steven Lu dipende dal tuo dispositivo. Ad esempio su quelli più recenti, come l'allocazione di iPhone5 o iPad4 a 70 Mb non è affatto un problema.
Max

1
sì, ma voglio sapere se posso essere sicuro che fino a quando mantengo l'utilizzo totale della mia app con il budget di memoria specifico del dispositivo magico che non verrà terminato!
Steven Lu,

1
non ci sono garanzie
Max

421

Risultati dei test con l'utilità Split scritto (il link è nella sua risposta):

dispositivo: (importo del crash / importo totale / percentuale del totale)

  • 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 1a generazione: 297 MB / 512 MB / 58%
  • Retina iPad Mini: 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, 1TB): 4598/5650/81% (iOS 12.1)
  • iPad 10.2: 1844/2998/62% (iOS 13.2.3)
  • iPod touch di quarta generazione: 130 MB / 256 MB / 51% (iOS 6.1.1)
  • iPod touch di quinta generazione: 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)
  • iPhone7: 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)

2
iPhone4: valore simile confermato, sembra legittimo: P
cprcrack

3
iPhone 5 si arresta in modo anomalo a ± 645 MB.
asp_net,

4
@JasperPol Ho modificato il tuo post per includere vari dispositivi che ho, spero che vada bene. Ho aggiunto la versione iOS su cui ho provato nel caso in cui sia importante, ma sentiti libero di rimuoverlo se ritieni che non sia importante.
Joseph H,

2
Fantastico che questo elenco sia stato creato e gestito. Nella mia esperienza, ho dovuto mantenere la memoria molto più bassa per essere sicuro, forse il 20% di ciò che viene mostrato qui. Anche le differenze da dispositivo a dispositivo sono molto variabili.
user1021430

1
Ho appena eseguito questo su un iPad Pro 12.9. Avviso di memoria a 2451 MB, crash a 3064 MB, totale 3981 MB.
blocco

134

Ho creato una piccola utility che tenta di allocare quanta più memoria possibile all'arresto anomalo e registra quando si verificano avvisi e arresti anomali della memoria. Questo aiuta a scoprire qual è il budget di memoria per qualsiasi dispositivo iOS.

https://github.com/Split82/iOSMemoryBudgetTest


Ho fatto un test interessante: ho eseguito la mia app con l'utilizzo della memoria di monitoraggio xcode, ho inserito lo sfondo, eseguito BudgetTest. Il test è stato interrotto mentre la mia app in background non lo era. Sono interessato a sapere perché. Inoltre, questo va contro ciò che @cprcrack ha detto nell'altra risposta.
Roberto,

19

Nella mia app, l'esperienza utente è migliore se viene utilizzata più memoria, quindi devo decidere se davvero dovrei liberare tutta la memoria che posso dentro didReceiveMemoryWarning. Sulla base della risposta di Split e Jasper Pol, l'utilizzo di un massimo del 45% della memoria totale del dispositivo sembra essere una soglia sicura (grazie ragazzi).

Nel caso in cui qualcuno desideri esaminare la mia effettiva implementazione:

#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 (basato su questa risposta ):

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
}

1
la dimensione dovrebbe essere TASK_BASIC_INFO_COUNT invece di sizeof (informazioni) - questo errore viene copiato e incollato in molti punti con lo stesso codice
Maxim Kholyavkin il

Grazie Speakus. Sembra che tu abbia ragione sulla base di questo link . Hai altri riferimenti in cui è possibile trovare queste informazioni?
cprcrack,

apple utilizza anche
Maxim Kholyavkin il

Il 45% non è più un limite sicuro, è troppo vicino al 50% del valore di crash per iPhone X. Suggerisco di utilizzare il 40% o un valore separato per ciascun dispositivo.
Slyv,

8

Forking repository SPLITS, ne ho creato uno per testare la memoria iOS che può essere allocata all'estensione di oggi

iOSMemoryBudgetTestForExtension

Di seguito è riportato il risultato che ho ottenuto in iPhone 5s

Avviso di memoria a 10 MB

App bloccata a 12 MB

Ciò significa che Apple sta semplicemente permettendo a qualsiasi estensione di funzionare con il suo pieno potenziale .


7

Dovresti guardare la sessione 147 dai video della sessione del WWDC 2010 . È "Advanced Performance Optimization su iPhone OS, parte 2".
Ci sono molti buoni consigli sulle ottimizzazioni della memoria.

Alcuni dei suggerimenti sono:

  • Usa NSAutoReleasePools nidificati per assicurarti che l'utilizzo della memoria non aumenti.
  • Utilizzare CGImageSourcequando si creano miniature da immagini di grandi dimensioni.
  • Rispondere agli avvisi di memoria insufficiente.

La mia domanda non è su come ottimizzare (grazie per il link), ma su quanto possiamo permetterci di usare. Il motivo è che, ad esempio, se ottimizziamo per guadagnare 20 MB, gli artisti vorranno utilizzare quel 20 MB se rientra nel "budget" ragionevole, ovvero sicuro che non causerà problemi di prestazioni o crash della memoria.
frilla,

OK. L'incidente sarà dovuto al fatto che il sistema operativo sta terminando l'app a causa della memoria limitata. Potresti semplicemente aggiungere un NSLoginterno didReceiveMemoryWarninge quindi fare dei test in cui allocare diverse quantità di memoria e quindi vedere quando iniziano gli avvisi di memoria.
Kobski

4

A partire da iOS13, esiste un modo supportato da Apple di interrogare questo utilizzando

#include <os/proc.h>

size_t os_proc_available_memory(void)

Introdotto qui: https://developer.apple.com/videos/play/wwdc2019/606/

Intorno min 29-ish.

Modifica: aggiunta del collegamento alla documentazione https://developer.apple.com/documentation/os/3191911-os_proc_available_memory?language=objc


Finalmente! Ho testato os_proc_available_memory () su alcuni dispositivi, e i risultati sono molto simili ai valori nella tabella sopra!
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;
}

Se uno utilizzerà TASK_BASIC_INFO_COUNT invece di MACH_TASK_BASIC_INFO, otterrai

kerr == KERN_INVALID_ARGUMENT (4)


Dovresti almeno menzionare che la tua risposta è quasi una copia e incolla esatta di @ cprcrack's sopra. L'unica differenza è TASK_BASIC_INFO_COUNT.
mrvincenzo,

2

Ho creato un altro elenco ordinando l'elenco Jaspers in base alla RAM del dispositivo (ho effettuato i miei test con lo strumento Split e corretto alcuni risultati - controlla i miei commenti nel thread Jaspers).

RAM del dispositivo: intervallo percentuale in crash

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

Casi speciali:

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

La RAM del dispositivo può essere letta facilmente:

[NSProcessInfo processInfo].physicalMemory

Dalla mia esperienza è sicuro utilizzare il 45% per i dispositivi da 1 GB, il 50% per i dispositivi da 2/3 GB e il 55% per i dispositivi da 4 GB. La percentuale di macOS può essere un po 'più grande.


aggiornamento: sembra che iPhone X sia un'eccezione: si arresta in modo anomalo quando viene utilizzato il 50% di RAM (testato con l'app iOSMemoryBudgetTest). Ho aggiornato l'elenco.
Slyv,

0

Lavorando con le molte risposte sopra, ho implementato il nuovo metodo Apples os_proc_available_memory()per iOS 13+ insieme al NSByteCountFormatterquale offre una serie di utili opzioni di formattazione per un migliore output della memoria:

#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]);
    }
}

Nota importante: non dimenticare il ()alla fine. Ho incluso entrambe le NSLogopzioni nel memoryLoggingOutputmetodo perché non ti avverte che mancano e la mancata inclusione delle parentesi restituisce un risultato imprevisto ma costante.

La stringa restituita dal metodo memoryStringForBytesgenera valori in questo modo:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.