presupuesto de memoria máxima de la aplicación ios

152

Estoy trabajando en un juego ios que apunta como mínimo a 3gs. Estamos utilizando recursos HD para dispositivos de visualización de retina (iphone 4, ipod touch 4th gen).

En cuanto a la memoria, Ipod Touch 4th gen parece ser el dispositivo más limitado para nosotros, ya que tiene la misma cantidad de RAM (256 en comparación con 512 de Iphone 4) que 3gs, pero estamos usando activos HD en él. La aplicación solía bloquearse cuando intentaba cargar 100-110 mb de RAM, pero ahora que hemos reducido a 70 MB, nunca hemos tenido un bloqueo de carga.

Después de muchas búsquedas, parece que no hay un límite oficial estricto, entonces, ¿cómo debemos saber qué presupuesto de memoria usar para estar a salvo? Queremos poder dar a los artistas un presupuesto que puedan usar sin problemas de memoria para cada mapa.

frilla
fuente
1
Posible duplicado de la asignación de memoria
nhgrif
14
No estoy seguro de cómo esta pregunta puede ser un duplicado de algo que se hizo en un momento posterior.
Jasper

Respuestas:

42

Creo que ha respondido su propia pregunta: trate de no ir más allá del límite de 70 Mb, sin embargo, realmente depende de muchas cosas: qué versión de iOS está usando (no SDK), cuántas aplicaciones se ejecutan en segundo plano, qué memoria exacta estás usando etc.

Solo evite las salpicaduras instantáneas de memoria (por ejemplo, está utilizando 40 Mb de RAM y luego asigna 80 Mb más para un cálculo corto). En este caso, iOS mataría su aplicación de inmediato.

También debe considerar la carga diferida de activos (cárguelos solo cuando realmente lo necesite y no de antemano).

Max
fuente
2
Es solo que queríamos poner tantas cosas como pudiéramos (gráficos y sonidos). Los artistas siempre querrán poner todo lo que puedan en un juego, por eso quiero limitarlos con un presupuesto. Supongo que tendremos que probar en muchos dispositivos diferentes en diferentes configuraciones para encontrar una huella de memoria máxima razonable para usar.
Frilla 05 de
2
¿Asignar solo 70 MB (que presumiblemente está por debajo del presupuesto) en cualquier momento en ese dispositivo (incluso después de un uso intensivo en otras aplicaciones que consumen mucha memoria) siempre garantizará una asignación exitosa, o todavía se bloqueará?
Steven Lu
1
@ Steven Lu depende de tu dispositivo. Por ejemplo, en los más nuevos, como iPhone5 o iPad4, la asignación de 70 Mb no es un problema en absoluto.
Max
1
Sí, pero quiero saber si puedo estar seguro de que, siempre y cuando mantenga el uso total de mi aplicación bajo el presupuesto de memoria específico del dispositivo mágico, no se cancelará.
Steven Lu
1
no hay garantías
Max
421

Resultados de las pruebas con la utilidad Split escribió (el enlace está en su respuesta):

dispositivo: (cantidad de bloqueo / cantidad total / porcentaje del total)

  • iPad1: 127MB / 256MB / 49%
  • iPad2: 275MB / 512MB / 53%
  • iPad3: 645MB / 1024MB / 62%
  • iPad4: 585MB / 1024MB / 57% (iOS 8.1)
  • iPad Mini de primera generación: 297 MB / 512 MB / 58%
  • iPad Mini retina: 696MB / 1024MB / 68% (iOS 7.1)
  • iPad Air: 697MB / 1024MB / 68%
  • iPad Air 2: 1383MB / 2048MB / 68% (iOS 10.2.1)
  • iPad Pro 9.7 ": 1395MB / 1971MB / 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 4ta generación: 130MB / 256MB / 51% (iOS 6.1.1)
  • iPod touch 5ta generación: 286MB / 512MB / 56% (iOS 7.0)
  • iPhone4: 325MB / 512MB / 63%
  • iPhone4s: 286MB / 512MB / 56%
  • iPhone5: 645MB / 1024MB / 62%
  • iPhone5s: 646MB / 1024MB / 63%
  • iPhone6: 645MB / 1024MB / 62% (iOS 8.x)
  • iPhone6 ​​+: 645MB / 1024MB / 62% (iOS 8.x)
  • iPhone6s: 1396MB / 2048MB / 68% (iOS 9.2)
  • iPhone6s +: 1392MB / 2048MB / 68% (iOS 10.2.1)
  • iPhoneSE: 1395MB / 2048MB / 69% (iOS 9.3)
  • iPhone7: 1395 / 2048MB / 68% (iOS 10.2)
  • iPhone7 +: 2040MB / 3072MB / 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)
Jaspe
fuente
2
iPhone4: valor similar confirmado, parece legítimo: P
cprcrack
3
iPhone 5 se bloquea a ± 645 MB.
asp_net
44
@JasperPol He editado tu publicación para incluir varios dispositivos que tengo, espero que esté bien. He agregado la versión de iOS que probé en caso de que sea importante, pero siéntase libre de eliminarla si cree que no es importante.
JosephH
2
Impresionante que esta lista haya sido creada y mantenida. En mi experiencia, he tenido que mantener la memoria mucho más baja para estar seguro, tal vez el 20% de lo que se muestra aquí. Las diferencias de dispositivo a dispositivo también son muy variables.
user1021430
1
Acabo de ejecutar esto en un iPad Pro 12.9. Advertencia de memoria a 2451 MB, bloqueo a 3064 MB, total de 3981 MB.
bloqueo
134

Creé una pequeña utilidad que intenta asignar la mayor cantidad de memoria posible al bloqueo y registra cuándo ocurrieron las advertencias de memoria y el bloqueo. Esto ayuda a descubrir cuál es el presupuesto de memoria para cualquier dispositivo iOS.

https://github.com/Split82/iOSMemoryBudgetTest

División
fuente
Hice una prueba interesante: ejecuté mi aplicación con el uso de memoria de monitoreo de xcode, ingresé el fondo, ejecuté el BudgetTest. La prueba fue cancelada mientras que mi aplicación en segundo plano no. Estoy interesado en saber por qué. Además, esto va en contra de lo que @cprcrack dijo en la otra respuesta.
Roberto
19

En mi aplicación, la experiencia del usuario es mejor si se usa más memoria, por lo que tengo que decidir si realmente debería liberar toda la memoria que pueda endidReceiveMemoryWarning . Según la respuesta de Split y Jasper Pol, usar un máximo del 45% de la memoria total del dispositivo parece ser un umbral seguro (gracias, muchachos).

En caso de que alguien quiera ver mi implementación real:

#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 (basado en esta respuesta ):

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
fuente
1
el tamaño debe ser TASK_BASIC_INFO_COUNT en lugar de sizeof (información) - este error se copió en muchos lugares con el mismo código
Maxim Kholyavkin
Gracias Speakus Parece que tienes razón en este enlace . ¿Tiene alguna otra referencia para encontrar esta información?
cprcrack
usos manzana TASK_BASIC_INFO_COUNT demasiado
Maxim Kholyavkin
45% ya no es un límite seguro, está demasiado cerca del valor de bloqueo del 50% para iPhone X. Sugiero usar 40% o un valor separado para cada dispositivo.
Slyv
8

Al bifurcar el repositorio SPLITS, construí uno para probar la memoria de iOS que se puede asignar a la Extensión de hoy

iOSMemoryBudgetTestForExtension

El siguiente es el resultado que obtuve en iPhone 5s

Advertencia de memoria a 10 MB

Aplicación bloqueada a 12 MB

De esta manera, Apple simplemente permite que cualquier extensión funcione con todo su potencial .

Duro
fuente
7

Debería ver la sesión 147 de los videos de la sesión de WWDC 2010 . Es "Optimización de rendimiento avanzada en iPhone OS, parte 2".
Hay muchos buenos consejos sobre optimizaciones de memoria.

Algunos de los consejos son:

  • Usar anidado NSAutoReleasePool s para asegurarse de que su uso de memoria no aumente.
  • Úselo CGImageSourceal crear miniaturas a partir de imágenes grandes.
  • Responda a las advertencias de poca memoria.
Kobski
fuente
Mi pregunta no es sobre cómo optimizar (aunque gracias por el enlace), se trata de cuánto podemos permitirnos usar. La razón es que, por ejemplo, si optimizamos para ganar 20 MB, los artistas querrán usar ese 20 MB si está dentro del "presupuesto" razonable, es decir, seguro de que no causará ningún problema de rendimiento o bloqueo de memoria.
Frilla 05 de
OKAY. El bloqueo se debe a que el sistema operativo está finalizando la aplicación debido a la memoria limitada. Simplemente puede agregar un NSLoginterior didReceiveMemoryWarningy luego hacer algunas pruebas en las que asigna diferentes cantidades de memoria y luego ver cuándo comienzan a aparecer las advertencias de memoria.
Kobski 05 de
4

A partir de iOS13, hay una forma compatible de Apple de consultar esto mediante el uso de

#include <os/proc.h>

size_t os_proc_available_memory(void)

Introducido aquí: https://developer.apple.com/videos/play/wwdc2019/606/

Alrededor de min 29-ish.

Editar: Agregar enlace a la documentación https://developer.apple.com/documentation/os/3191911-os_proc_available_memory?language=objc

Exaberri Tokugawa
fuente
¡Finalmente! ¡Probé os_proc_available_memory () en algunos dispositivos, y los resultados son muy similares a los valores de la tabla grande de arriba!
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;
}

Si uno usa TASK_BASIC_INFO_COUNT en lugar de MACH_TASK_BASIC_INFO, obtendrá

kerr == KERN_INVALID_ARGUMENT (4)

Dmitry Preobrazhenskiy
fuente
Al menos debería mencionar que su respuesta es casi una copia exacta y pegar de @ cprcrack de arriba. La única diferencia es TASK_BASIC_INFO_COUNT.
mrvincenzo
2

Creé una lista más clasificando la lista de Jaspers por la RAM del dispositivo (hice mis propias pruebas con la herramienta Split y arreglé algunos resultados; revise mis comentarios en el hilo de Jaspers).

RAM del dispositivo: rango de porcentaje para bloquearse

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

Casos especiales:

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

La RAM del dispositivo se puede leer fácilmente:

[NSProcessInfo processInfo].physicalMemory

Según mi experiencia, es seguro usar el 45% para dispositivos de 1GB, el 50% para dispositivos de 2 / 3GB y el 55% para dispositivos de 4GB. El porcentaje para macOS puede ser un poco más grande.

Slyv
fuente
actualización: Parece que el iPhone X es una excepción: se bloquea cuando se usa el 50% de la RAM (probado con la aplicación iOSMemoryBudgetTest). Actualicé la lista.
Slyv
0

Trabajando con las muchas respuestas anteriores, he implementado el nuevo método os_proc_available_memory()de Apple para iOS 13+ junto con el NSByteCountFormattercual ofrece una serie de opciones de formato útiles para una mejor salida de la 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: No te olvides de ()al final. He incluido ambas NSLogopciones en elmemoryLoggingOutput método porque no le advierte que faltan y la falta de incluir los corchetes devuelve un resultado inesperado pero constante.

La cadena devuelta por el método memoryStringForBytesgenera valores como este:

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
fuente