новый оператор (как и malloc) не может выделить ~ 450 МБ памяти

Я работаю над программой, которая хранит в памяти массив из примерно 220 миллионов коротких значений. Этот блок данных распределяется следующим образом:

short * arrayName = new short[SIZE_OF_ARRAY];

Затем содержимое файла считывается в память. После большого масштабного обновления общей архитектуры программы другим человеком в команде именно эта строка начала вызывать сбой программы. Сообщение такое:

Microsoft Visual C++ Runtime Library
Runtime Error!
abnormal program termination

Это происходит сразу же при этом вызове выделения памяти (дальнейшие строки, такие как проверка, является ли указатель NULL, не выполняются). Даже через несколько дней нам неясно, какое именно изменение в другом коде привело к тому, что эта строка начала вести себя таким образом (на самом деле ничего, что даже отдаленно связано с этим массивом, не изменилось).

В Linux (точнее, в Ubuntu) все работает нормально; эта проблема существует только на машинах Windows. В 64-разрядных ОС Windows помогает этот обходной путь (в файле .pro):

QMAKE_LFLAGS_WINDOWS += /LARGEADDRESSAWARE

На 32-битной не помогает.

Замена строки на malloc следующим образом позволила мне проверить, является ли указатель NULL после нее (что так и есть), и получить код ошибки из errno, который равен 12 (ENOMEM) = «Недостаточно памяти».

short * arrayName = (short *)malloc(SIZE_OF_ARRAY * sizeof(short));

Этот StackOverflow вопрос кажется о той же проблеме; схожесть ее есть даже вплоть до того, что выделение меньшего объема памяти работает (а вот 450 Мб нет). Ответы там предполагали высокую фрагментацию памяти и то, что new / malloc не может выделить непрерывную область памяти, но в моем случае проблема сохраняется даже после перезагрузки, когда только ~ 600 МБ из 2 физических ГБ (и 4 виртуальных ГБ) были используется, поэтому это несколько исключено (к тому же, как я уже упоминал, точно такая же строка кода работала раньше).

Мое главное подозрение заключается в том, что это как-то связано с размером кучи (хотя я не уверен, что new и malloc выделяют память для кучи, а также я еще не нашел способ изменить размер кучи в Qt). Я что-то упустил здесь?


person Fy Zn    schedule 12.08.2013    source источник
comment
Какой компилятор вы используете?   -  person Kornel Kisielewicz    schedule 12.08.2013
comment
И new, и malloc резервируют память в куче. Ненормальное завершение вашей программы, скорее всего, является необработанным исключением bad_alloc.   -  person Greenflow    schedule 12.08.2013
comment
@KornelKisielewicz, MSVC2010.   -  person Fy Zn    schedule 12.08.2013
comment
Вы пытались разрезать дерево пополам, чтобы увидеть, какое изменение вызвало эту ошибку?   -  person greatwolf    schedule 12.08.2013
comment
@greatwolf, да, как я уже сказал, точная фиксация была обнаружена, но она включает изменения во многих файлах и во многих местах в архитектуре программы, которые все взаимосвязаны. Невозможно отменить их один за другим.   -  person Fy Zn    schedule 12.08.2013
comment
И кстати... возможно, что у вас закончилась память. 32-битная Windows довольно ограничена, когда речь идет об использовании памяти. Откройте монитор ресурсов и следите за использованием памяти.   -  person Greenflow    schedule 12.08.2013
comment
@ user2011734, я очень сомневаюсь в этом (с ~ 600 МБ, используемыми другими процессами, 2 ГБ физической памяти и общим ограничением в 4 ГБ (3 + 1 пользователь / система) виртуальной памяти на 32-разрядной версии). Тот же объем выделенной памяти всегда отлично работал на этой конкретной машине.   -  person Fy Zn    schedule 12.08.2013
comment
Если вы явно не настроите свой компилятор так, чтобы new возвращал указатель NULL при ошибке, это не так. Выдает исключение. И если вы не поймаете это исключение, ваша программа попрощается.   -  person Greenflow    schedule 12.08.2013
comment
@paxdiablo, спасибо за ссылку. Эта проблема действительно очень похожа, но в комментариях нет ответа, почему нельзя выделить относительно небольшой объем памяти (относительно доступной свободной памяти).   -  person Fy Zn    schedule 12.08.2013
comment
chris.pirillo.com/32-bit-windows-and -4 ГБ ОЗУ   -  person Greenflow    schedule 12.08.2013
comment
@user2011734 user2011734, у меня намного меньше отметки в 2 ГБ с этим. Максимальное использование ~ 1,2 ГБ (650 МБ других процессов + этот) на машине с 2 ГБ физической оперативной памяти.   -  person Fy Zn    schedule 12.08.2013
comment
Если ты так говоришь. :-) На вашем месте я бы проверил монитор ресурсов. Вы можете быть удивлены. Вот еще одна ссылка: stackoverflow.com/questions/5686459/   -  person Greenflow    schedule 12.08.2013
comment
Вот скриншот из Process Explorer во время работы программы (сделанный через пару секунд после сбоя, поэтому он должен быть крайним справа на графиках). i.imgur.com/wpliIZ4.png   -  person Fy Zn    schedule 12.08.2013
comment
Итак, вы пытаетесь выделить 450 МБ с помощью одного malloc/new? Это может привести к сбою в любое время, даже если общей свободной оперативной памяти кучи достаточно. Выполнение этого с помощью одного new/malloc требует 450 непрерывных кучи памяти. Поскольку куча фрагментирована, фрагментов такого размера может не быть.   -  person Frank Osterfeld    schedule 12.08.2013


Ответы (1)


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

/LARGEADDRESSAWARE сообщает ОС, что ваше приложение может принимать большее адресное пространство. Win64 предоставит приложениям Win32 3 ГБ адресного пространства, в Win32 это не является стандартом.

Отключение ASLR может помочь, поскольку оно будет загружать библиотеки DLL линейным образом (таким образом, с предсказуемыми смещениями, что является угрозой безопасности). С ASLR библиотеки DLL разбросаны по памяти. Поскольку всего 10 DLL разбросаны по 2 ГБ адресного пространства (а это нереально мало), среднее пространство между ними составляет ~ 200 МБ.

person MSalters    schedule 12.08.2013