Ответ Мартина Драб положил меня на правильный путь. Исследование о распределении кучи я нашел этот old message, разъясняющий, что происходит:
Проблемы здесь в том, что блоки над 512k являются прямыми вызовами VirtualAlloc, а все остальное меньше, чем это выделяются из из кучи сегментов. Плохая новость заключается в том, что сегменты никогда не выпустили (полностью или частично), поэтому те, что вы берете на себя весь адрес пространство с небольшими блоками вы не можете использовать их для других куч или блоков более 512 K.
проблемы не связан с Qt, но связан с Windows; Я мог бы, наконец, воспроизвести его с помощью простого std::vector
массивов символов. Распределитель кучи по умолчанию оставляет сегменты адресного пространства неизменными даже после того, как соответствующее распределение было явно выпущено. Соотношение состоит в том, что процесс может запрашивать снова буферы с аналогичным размером, а менеджер кучи сэкономит время на повторное использование существующих сегментов адресов вместо уплотнения старых для создания новых.
Обратите внимание, что это не имеет никакого отношения к количеству доступной физической или виртуальной памяти. Это только адресное пространство, которое остается сегментированным, хотя эти сегменты бесплатны.Это серьезная проблема для 32-битных архитектур, где адресное пространство составляет всего 2 ГБ (может быть 3).
Именно поэтому память была отмечена как «частная», даже после ее освобождения и, по-видимому, не пригодна для использования одним и тем же процессом для среднеразмерных маллоков, хотя зафиксированная память была очень низкой.
Чтобы воспроизвести проблему, просто создайте огромный вектор кусков размером меньше 512 КБ (они должны быть выделены с помощью new или malloc). После того, как память будет заполнена и затем отпущена (независимо от того, достигнут ли предел, а исключение поймано или память просто заполнена без ошибок), процесс не сможет выделить ничего большего, чем 512Kb. Память свободна, она назначается одному процессу («частный»), но все ведра слишком малы.
Но есть и худшие новости: по-видимому, нет никакого способа заставить уплотнение сегментов кучи. Я пробовал с this и this, но не повезло; точного эквивалента POSIX fork()
(см. here и here). Единственное решение - сделать что-то более низкое, например creating a private heap, и уничтожить его после небольших распределений (как это предложено в приведенном выше сообщении) или реализовать пользовательский распределитель (там может быть какое-то коммерческое решение). Оба совершенно неосуществимы для большого, существующего программного обеспечения, где самым простым решением является закрытие процесса и его перезапуск.
win32 никогда не «задерживает» выпуск - если вы вызываете 'VirtualFree (p, 0, MEM_RELEASE)' - память будет выпущена при возврате функции (в случае, если курсор 'p' правильный) - так 100%' VirtualFree' не был вызван или вызван с плохим аргументом – RbMm
'QList'' QList's ** what **? Это важно здесь. –
"QVariant". Это в основном электронная таблица. Он обычно содержит числа в виде строк или URL-адресов. – Narcolessico