максимальный бюджет памяти приложения ios

152

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

Что касается памяти, Ipod Touch 4-го поколения представляется нам наиболее ограничивающим устройством, поскольку он имеет такой же объем ОЗУ (256 по сравнению с 512 в Iphone 4), что и 3gs, но мы используем HD-ресурсы на нем. Раньше приложение зависало при попытке загрузить 100-110 МБ оперативной памяти, но теперь, когда у нас осталось 70 МБ, у нас никогда не возникало аварийного завершения загрузки.

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

frilla
источник
14
Не уверен, как этот вопрос может быть дубликатом чего-то, что было задано позднее.
Джаспер

Ответы:

42

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

Просто избегайте мгновенных всплесков памяти (например, вы используете 40 МБ ОЗУ, а затем выделяете еще 80 МБ для некоторых коротких вычислений). В этом случае iOS немедленно убьет ваше приложение.

Вы также должны рассмотреть ленивую загрузку активов (загружайте их только тогда, когда вам действительно нужно, а не заранее).

Максимум
источник
2
Просто мы хотели разместить как можно больше материала (графика и звуки). Артисты всегда хотят вкладывать в игру как можно больше, поэтому я хочу ограничить их бюджетом. Я думаю, нам просто нужно протестировать на разных устройствах в разных настройках, чтобы найти разумный максимальный объем памяти для использования.
Фрила
2
Будет ли выделение только 70 МБ (что, по-видимому, в рамках бюджета) в любое время на этом устройстве (даже после интенсивного использования в других приложениях, требующих памяти) всегда гарантировать успешное выделение или оно все еще может привести к сбою?
Стивен Лу
1
@ Стивен Лу, это зависит от вашего устройства. Например, на более новых, таких как iPhone5 или iPad4, 70 Мб выделения не проблема.
Макс
1
да, но я хочу знать, могу ли я быть уверен в том, что, пока я сохраняю общее использование моего приложения в рамках бюджета памяти магического устройства, оно не будет прекращено!
Стивен Лу
1
нет никаких гарантий
Макс
421

Результаты тестирования с помощью утилиты Split написал (ссылка в его ответе):

устройство: (количество аварий / общая сумма / процент от общего)

  • iPad1: 127 МБ / 256 МБ / 49%
  • iPad2: 275 МБ / 512 МБ / 53%
  • iPad3: 645 МБ / 1024 МБ / 62%
  • iPad4: 585 МБ / 1024 МБ / 57% (iOS 8.1)
  • iPad Mini 1-го поколения: 297 МБ / 512 МБ / 58%
  • Сетчатка iPad Mini: 696 МБ / 1024 МБ / 68% (iOS 7.1)
  • iPad Air: 697 МБ / 1024 МБ / 68%
  • iPad Air 2: 1383 МБ / 2048 МБ / 68% (iOS 10.2.1)
  • iPad Pro 9.7 ": 1395 МБ / 1971 МБ / 71% (iOS 10.0.2 (14A456))
  • iPad Pro 10,5 ”: 3057/4000/76% (iOS 11 бета4)
  • iPad Pro 12,9 ”(2015): 3058/3999/76% (iOS 11.2.1)
  • iPad Pro 12,9 ”(2017): 3057/3974/77% (iOS 11 бета4)
  • 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-го поколения: 286 МБ / 512 МБ / 56% (iOS 7.0)
  • iPhone4: 325 МБ / 512 МБ / 63%
  • iPhone4s: 286 МБ / 512 МБ / 56%
  • iPhone5: 645 МБ / 1024 МБ / 62%
  • iPhone5s: 646 МБ / 1024 МБ / 63%
  • iPhone6: 645 МБ / 1024 МБ / 62% (iOS 8.x)
  • iPhone6 ​​+: 645 МБ / 1024 МБ / 62% (iOS 8.x)
  • iPhone6s: 1396 МБ / 2048 МБ / 68% (iOS 9.2)
  • iPhone6s +: 1392 МБ / 2048 МБ / 68% (iOS 10.2.1)
  • iPhoneSE: 1395 МБ / 2048 МБ / 69% (iOS 9.3)
  • iPhone7: 1395/2048 МБ / 68% (iOS 10.2)
  • iPhone7 +: 2040 МБ / 3072 МБ / 66% (iOS 10.2.1)
  • iPhone8: 1364/1990 МБ / 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: аналогичное значение подтверждено, кажется законным: P
cprcrack
3
iPhone 5 вылетает на уровне ± 645 МБ.
asp_net
4
@JasperPol Я отредактировал ваше сообщение, добавив в него различные устройства, надеюсь, все в порядке. Я добавил версию для iOS, на которой протестировал, если это имеет значение, но вы можете удалить ее, если считаете, что это не важно.
JosephH
2
Удивительно, что этот список был создан и поддерживается. По моему опыту, мне пришлось держать память намного ниже, чтобы быть в безопасности, может быть, 20% от того, что показано здесь. Различия между устройствами также сильно различаются.
user1021430
1
Просто запустил это на 12,9 iPad Pro. Предупреждение о памяти на 2451MB, сбой на 3064MB, всего 3981MB.
блокировка
134

Я создал небольшую утилиту, которая пытается выделить как можно больше памяти для сбоя и записывает, когда произошли предупреждения и сбой памяти. Это помогает выяснить, каков бюджет памяти для любого устройства iOS.

https://github.com/Split82/iOSMemoryBudgetTest

Трещина
источник
Я сделал интересный тест: запустил свое приложение с использованием памяти мониторинга xcode, ввел фон, запустил BudgetTest. Тест был убит, а мое приложение в фоновом режиме - нет. Мне интересно знать почему. Кроме того, это противоречит тому, что @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
}
cprcrack
источник
1
size должен быть TASK_BASIC_INFO_COUNT вместо sizeof (info) - эта ошибка скопирована во многие места с одинаковым кодом
Максим Холявкин
Спасибо, Спикус. Похоже, вы правы, основываясь на этой ссылке . У вас есть другие ссылки, где можно найти эту информацию?
cprcrack
Apple тоже
Максим Холявкин
45% больше не является безопасным пределом, оно слишком близко к 50% -ному значению сбоя для iPhone X. Я предлагаю использовать 40% или отдельное значение для каждого устройства.
Слив
8

Разветвив репозиторий SPLITS, я построил один для тестирования памяти iOS, который можно выделить для сегодняшнего расширения.

iOSMemoryBudgetTestForExtension

Ниже приводится результат, который я получил в iPhone 5s

Память Предупреждение на 10 МБ

Приложение разбилось на 12 МБ

Таким образом, Apple просто позволяет любым расширениям работать в полную силу .

жесткий
источник
7

Вы должны смотреть сессию 147 из видео сессий WWDC 2010 . Это «Продвинутая оптимизация производительности на iPhone OS, часть 2».
Есть много хороших советов по оптимизации памяти.

Вот некоторые из советов:

  • Использовать вложенные NSAutoReleasePool s, чтобы убедиться, что использование памяти не увеличивается.
  • Используйте CGImageSourceпри создании миниатюр из больших изображений.
  • Реагируйте на предупреждения о недостатке памяти.
Kobski
источник
Мой вопрос не о том, как оптимизировать (спасибо за ссылку), а о том, сколько мы можем позволить себе использовать. Причина в том, что, например, если мы оптимизируем, чтобы получить 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.
Мрвинченцо
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 (4096 МБ): 55%
  • iPhone XR (3072 МБ): 63%
  • iPhone 11/11 Pro Max (4096 МБ): 54% - 55%

ОЗУ устройства можно легко прочитать:

[NSProcessInfo processInfo].physicalMemory

Исходя из моего опыта, можно безопасно использовать 45% для устройств с 1 ГБ, 50% для устройств с 2/3 ГБ и 55% для устройств с 4 ГБ. Процент для macOS может быть немного больше.

Slyv
источник
обновление: кажется, что 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
App Dev Guy
источник