Как может произойти сбой распределения памяти умеренного размера в 64-битном процессе в Mac OS X? - PullRequest
12 голосов
/ 02 марта 2011

Я создаю приложение макета фотокниги. Приложение часто распаковывает изображения JPEG в буферы растрового изображения в памяти. Размер изображений ограничен до 100 мегапикселей (хотя обычно они не превышают 15 мегапикселей).

Иногда выделение памяти для этих буферов завершается неудачно: [[NSMutableData alloc] initWithLength:] возвращает nil. Похоже, это происходит в ситуациях, когда свободная физическая память системы приближается к нулю.

Мое понимание системы виртуальной памяти в Mac OS X заключалось в том, что распределение в 64-битном процессе практически (sic) не может завершиться неудачей. Существует 16 эксабайт адресного пространства, из которых я пытаюсь выделить максимум 400 мегабайт за раз. Теоретически я мог бы выделить 40 миллиардов этих буферов, не превышая жесткого предела доступного адресного пространства. Конечно, практические ограничения помешают этому сценарию, поскольку пространство подкачки ограничено размером загрузочного тома. На самом деле я делаю только очень мало из этих ассигнований (менее десяти).

Что я не понимаю, так это тот факт, что распределение не выполняется, независимо от того, насколько мало физической памяти в этот момент. Я подумал, что, если осталось место подкачки, выделение памяти не завершится неудачей (поскольку на этом этапе страницы даже не отображаются).

Приложение является сборщиком мусора.

Edit:

У меня было время немного углубиться в эту проблему, и вот мои выводы:

  1. Проблема возникает только в процессе сборки мусора.
  2. При неудачном выделении из NSMutableData обычному malloc все равно удается выделить тот же объем памяти.
  3. Ошибка всегда возникает, когда общая физическая память приближается к нулю (происходит обмен).

Я полагаю, NSData использует NSAllocateCollectable для выполнения выделения вместо malloc при работе под сборкой мусора.

Мой вывод из всего этого состоит в том, что сборщик не может выделить большие порции памяти, когда физическая память мала. Что, опять же, я не понимаю.

Ответы [ 6 ]

9 голосов
/ 02 апреля 2011

Ответ заключается в реализации libauto .

Начиная с OS X 10.6, для 64-разрядных платформ выделена область памяти объемом 8 Гб.Эта арена разделена пополам для больших (> = 128 КБ) и малых (<2048b) или средних (<128 КБ) ресурсов. </p>

Таким образом, в действительности на 10,6 у вас есть 4 ГБ памяти, доступной для больших выделений мусорасобрана память.На 10.5 размер арены был 32Gb , но Apple снизила этот размер до 8Gb на 10.6 .

1 голос
/ 11 марта 2011

Другое предположение, но, возможно, машина вашего коллеги настроена с более строгим максимальным объемом памяти для каждого пользовательского процесса.Чтобы проверить, введите

ulimit -a

В консоль.Для меня я получаю:

~ iainmcgin$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 266
virtual memory          (kbytes, -v) unlimited

Из моих настроек выше, кажется, нет ограничений на использование памяти для каждого процесса.По какой-то причине это может не относиться к вашему коллеге.

Я использую Snow Leopard:

~ iainmcgin$ uname -rs
Darwin 10.6.0
0 голосов
/ 11 марта 2011

Это может быть проблема фрагментации памяти. Возможно, на момент выделения не было доступно ни одного смежного блока размером 400 МБ?

Вы можете попытаться распределить эти большие блоки в самом начале жизненного цикла вашего приложения, прежде чем куча получит возможность фрагментироваться многочисленными меньшими выделениями.

0 голосов
/ 10 марта 2011

Возможно, вам не хватает места подкачки. Даже если у вас есть файл подкачки и виртуальная память, объем доступного пространства подкачки по-прежнему ограничен пространством на жестком диске для файлов подкачки.

0 голосов
/ 04 марта 2011

initWithBytes:length: пытается выделить всю его длину в активной памяти, по существу эквивалентную malloc() этого размера.Если длина превышает доступную память, вы получите ноль.Если вы хотите использовать большие файлы с NSData, я бы порекомендовал initWithContentsOfMappedFile: или аналогичные инициализаторы, поскольку они используют систему виртуальных машин для извлечения частей файла в активную память и из нее при необходимости.

0 голосов
/ 04 марта 2011

Несмотря на то, что 64-битный компьютер теоретически может адресовать 18 ЭБ, текущие процессоры ограничены 256 ТБ. Конечно, вы не достигаете этого предела. Но объем памяти, который ваш процесс может использовать за один раз, ограничен объемом доступной оперативной памяти. ОС также может ограничивать объем оперативной памяти, которую вы можете использовать. Согласно опубликованной вами ссылке: «Даже для компьютеров, на которых доступно 4 или более гигабайт оперативной памяти, система редко выделяет такой объем оперативной памяти одному процессу».

...