Максимальний бюджет пам’яті на додаток ios


152

Я працюю над грою на ios, яка орієнтована як мінімум на 3gs. Ми використовуємо активи HD для пристроїв відображення сітківки (iphone 4, ipod touch 4th gen).

Пам’ятаючи про пам'ять, Ipod Touch 4th gen, здається, є найбільш обмежуючим пристроєм для нас, оскільки він має таку ж кількість оперативної пам’яті (256 порівняно з 512 Iphone 4), як 3gs, але ми використовуємо HD активи на цьому. Додаток використовувався для збоїв при спробі завантажити 100-110 Мб оперативної пам'яті, але тепер, коли ми знизилися до 70 Мб, у нас ніколи не було аварійного завантаження.

Після численних пошуків навколо, здається, немає офіційного жорсткого обмеження, тож як нам піти про те, який бюджет пам'яті використовувати, щоб бути безпечним? Ми хочемо дати художникам бюджет, який вони зможуть використовувати, не турбуючись про пам’ять для кожної карти.



14
Не впевнений, яким чином це питання може бути дублікатом того, про що було задано пізніше.
Джаспер

Відповіді:


42

Я думаю, ви відповіли на власне запитання: намагайтеся не виходити за межу 70 Мб, проте це дійсно залежить від багатьох речей: яку версію iOS ви використовуєте (не SDK), скільки додатків, що працюють у фоновому режимі, яка точна пам'ять ви використовуєте і т.д.

Просто уникайте вкраплення миттєвої пам’яті (наприклад, ви використовуєте 40 Мб оперативної пам’яті, а потім виділяєте 80 Мб більше для коротких обчислень). У цьому випадку iOS негайно знищить вашу програму.

Ви також повинні врахувати ледачий навантаження активів (завантажуйте їх лише тоді, коли вам це справді потрібно, а не заздалегідь).


2
Просто ми хотіли поставити якомога більше матеріалів (графіка та звуки). Художники завжди захочуть вкласти в гру стільки, наскільки це можливо, тому я хочу обмежити їх бюджетом. Я думаю, що нам просто доведеться протестувати на багатьох різних пристроях в різних налаштуваннях, щоб знайти розумний максимальний слід пам'яті.
frilla

2
Чи буде виділення лише 70 МБ (що, імовірно, передбачено бюджетом) у будь-який час на цьому пристрої (навіть після великого використання в інших додатках, голодних пам’яті), завжди гарантуватиме успішне розподіл, або воно потенційно все-таки вийде з ладу?
Стівен Лу

1
@Steven Lu це залежить від вашого пристрою. Наприклад, про новіші, наприклад, iPhone5 або iPad4, виділення 70 Мб зовсім не є проблемою.
Макс

1
так, але я хочу знати, чи я можу бути впевнений, що поки я буду тримати загальне використання мого додатка під магічним бюджетом пам'яті конкретного пристрою, він не припиняється!
Стівен Лу

1
гарантій немає
Макс

421

Результати тестування з утилітою Split написали (посилання є у його відповіді):

пристрій: (сума аварії / загальна сума / відсоток від загальної кількості)

  • iPad1: 127MB / 256MB / 49%
  • iPad2: 275MB / 512MB / 53%
  • iPad3: 645MB / 1024MB / 62%
  • iPad4: 585MB / 1024MB / 57% (iOS 8.1)
  • iPad Mini 1-го покоління: 297MB / 512MB / 58%
  • Сітківка iPad Mini: 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, 1 ТБ): 4598/5650/81% (iOS 12.1)
  • iPad 10.2: 1844/2998/62% (iOS 13.2.3)
  • iPod touch 4-го покоління: 130 МБ / 256 МБ / 51% (iOS 6.1.1)
  • iPod touch 5-го покоління: 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)
  • iPhone6: 1396 МБ / 2048 МБ / 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: 2067/3740/55% (iOS 13.2.3)

2
iPhone4: подібне значення підтверджено, здається, законним: P
cprcrack

3
iPhone 5 виходить з ладу при ± 645 МБ.
asp_net

4
@JasperPol Я відредагував вашу публікацію, щоб включити різні пристрої, які у мене є, я сподіваюся, що це нормально. Я додав версію iOS, на яку я тестував, якщо це має значення, але сміливо видаліть її, якщо ви вважаєте, що це не важливо.
ЙосифГ

2
Дивно, що цей список створений та підтримується. На моєму досвіді я повинен був зберігати пам'ять набагато нижче, щоб бути безпечним, можливо 20% того, що тут показано. Відмінності пристрою до пристрою також сильно відрізняються.
користувач1021430

1
Щойно запустив це на 12,9 iPad Pro. Попередження про пам’ять на 2451 МБ, аварія на 3064 МБ, всього 3981 МБ.
замок

134

Я створив невелику утиліту, яка намагається виділити якомога більше пам’яті для збою, і вона записує, коли траплялися попередження та аварії пам'яті. Це допомагає дізнатися, який бюджет пам'яті для будь-якого пристрою iOS.

https://github.com/Split82/iOSMemoryBudgetTest


Я зробив цікавий тест: запустив свою програму з використанням моніторингу використання пам’яті xcode, увійшов до фону, запустив бюджетTest. Тест був убитий, поки мого фонового додатка не було. Мені цікаво знати, чому. Також це суперечить тому, що @cprcrack сказав в іншій відповіді.
Роберто

19

У моєму додатку користувальницький досвід краще, якщо використовується більше пам'яті, тому я повинен вирішити, чи дійсно потрібно звільнити всю пам'ять, в яку я можу didReceiveMemoryWarning. На основі відповіді Спліта та Джаспера Пол, використання максимум 45% всієї пам’яті пристрою є безпечним порогом (дякую хлопці).

У випадку, якщо хтось хоче переглянути мою реальну реалізацію:

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

Швидкий (на основі цієї відповіді ):

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
розмір повинен бути TASK_BASIC_INFO_COUNT замість sizeof (інформація) - цю помилку скопіювали у багато місць з тим самим кодом
Максим Холявкін

Спасибі Спикус. Ви, здається, маєте рацію на основі цього посилання . Чи є у вас інші посилання, де можна знайти цю інформацію?
cprcrack


45% не є безпечним обмеженням, це занадто близько до 50% значення аварії для iPhone X. Я пропоную використовувати 40% або окреме значення для кожного пристрою.
Слив

8

Формуючи SPLITS repo, я створив одну для тестування пам’яті iOS, яку можна виділити на сьогоднішнє розширення

iOSMemoryBudgetTestForExtension

Далі є результат, який я отримав в iPhone 5s

Попередження про пам’ять на 10 Мб

Додаток розбито в 12 Мб

Таким чином, Apple просто дозволяє будь-яким розширенням працювати з усім своїм потенціалом .


7

Ви можете подивитися сеанс 147 з відеозаписів сесії WWDC 2010 . Це "Розширена оптимізація продуктивності на iPhone OS, частина 2".
Є багато хороших порад щодо оптимізації пам’яті.

Деякі поради:

  • Використовуйте вкладені NSAutoReleasePools, щоб переконатися, що використання вашої пам’яті не зростає.
  • Використовуйте CGImageSourceдля створення мініатюр із великих зображень.
  • Відповідайте на попередження з низькою пам’яттю.

Моє питання не в тому, як оптимізувати (хоча спасибі за посилання), а в тому, скільки ми можемо дозволити собі використовувати. Причина полягає в тому, що, наприклад, якщо ми оптимізуємо для отримання 20 Мб, то художники захочуть використовувати цей 20 Мб, якщо він знаходиться в межах розумного "бюджету", але впевнений, що це не спричинить жодних проблем з продуктивністю або збою пам'яті.
фрілла

ГАРАЗД. Збій відбудеться тому, що ОС закінчує додаток через обмежену пам’ять. Ви можете просто додати NSLogвсередину, didReceiveMemoryWarningа потім зробити тестування, де ви виділяєте різні обсяги пам’яті, а потім побачити, коли починають
надходити

4

Починаючи з iOS13, існує підтримуваний Apple спосіб запиту цього за допомогою

#include <os/proc.h>

size_t os_proc_available_memory(void)

Представлено тут: https://developer.apple.com/videos/play/wwdc2019/606/

Приблизно хвилин 29-іш.

Редагувати: додавання посилання на документацію https://developer.apple.com/documentation/os/3191911-os_proc_available_memory?language=objc


Нарешті! Я тестував os_proc_available_memory () на кількох пристроях, і результати дуже схожі на значення у великій таблиці вище!
Слив

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

Якщо ви будете використовувати TASK_BASIC_INFO_COUNT замість MACH_TASK_BASIC_INFO, ви отримаєте

kerr == KERN_INVALID_ARGUMENT (4)


Принаймні слід згадати, що ваша відповідь є майже точною копією та вставкою вищевказаного @ cprcrack . Єдина відмінність - TASK_BASIC_INFO_COUNT.
mrvincenzo

2

Я створив ще один список, сортувавши список Jaspers за допомогою оперативної пам’яті пристрою (я робив власні тести за допомогою інструмента Split і зафіксував деякі результати - перевірити свої коментарі в темі Jaspers).

ОЗП пристрою: відсотковий діапазон до аварії

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

Особливі випадки:

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

Оперативну пам'ять пристрою можна легко прочитати:

[NSProcessInfo processInfo].physicalMemory

З мого досвіду безпечно використовувати 45% для пристроїв 1 ГБ, 50% для пристроїв 2/3 ГБ і 55% для пристроїв 4 ГБ. Відсоток для macOS може бути трохи більшим.


оновлення: Схоже, iPhone X є винятком - він виходить з ладу, коли використовується 50% оперативної пам’яті (протестовано за допомогою програми iOSMemoryBudgetTest). Я оновив список.
Слив

0

Працюючи з безліччю відповідей вище, я реалізував новий метод Apples os_proc_available_memory()для iOS 13+ у поєднанні, NSByteCountFormatterякий пропонує ряд корисних варіантів форматування для кращого виведення пам'яті:

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

Важлива примітка: Не забувайте ()в кінці. Я включив обидва NSLogваріанти в memoryLoggingOutputметод, тому що він не попереджає вас про відсутність, а невключення дужок повертає несподіваний, але постійний результат.

Рядок, що повертається з методу, memoryStringForBytesвиводить такі значення, як:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.