Я создаю приложение макета фотокниги. Приложение часто распаковывает изображения JPEG в буферы растрового изображения в памяти. Размер изображений ограничен до 100 мегапикселей (хотя обычно они не превышают 15 мегапикселей).
Иногда выделение памяти для этих буферов завершается неудачно: [[NSMutableData alloc] initWithLength:]
возвращает nil
. Похоже, это происходит в ситуациях, когда свободная физическая память системы приближается к нулю.
Мое понимание системы виртуальной памяти в Mac OS X заключалось в том, что распределение в 64-битном процессе практически (sic) не может завершиться неудачей. Существует 16 эксабайт адресного пространства, из которых я пытаюсь выделить максимум 400 мегабайт за раз. Теоретически я мог бы выделить 40 миллиардов этих буферов, не превышая жесткого предела доступного адресного пространства. Конечно, практические ограничения помешают этому сценарию, поскольку пространство подкачки ограничено размером загрузочного тома. На самом деле я делаю только очень мало из этих ассигнований (менее десяти).
Что я не понимаю, так это тот факт, что распределение не выполняется, независимо от того, насколько мало физической памяти в этот момент. Я подумал, что, если осталось место подкачки, выделение памяти не завершится неудачей (поскольку на этом этапе страницы даже не отображаются).
Приложение является сборщиком мусора.
Edit:
У меня было время немного углубиться в эту проблему, и вот мои выводы:
- Проблема возникает только в процессе сборки мусора.
- При неудачном выделении из
NSMutableData
обычному malloc
все равно удается выделить тот же объем памяти.
- Ошибка всегда возникает, когда общая физическая память приближается к нулю (происходит обмен).
Я полагаю, NSData
использует NSAllocateCollectable
для выполнения выделения вместо malloc
при работе под сборкой мусора.
Мой вывод из всего этого состоит в том, что сборщик не может выделить большие порции памяти, когда физическая память мала. Что, опять же, я не понимаю.