QVector (или std::vector) зарезервировать (или изменить размер) вниз не освобождает память

Скажем, у меня есть QVector, и я вызываю QVector::reserve для 420000 элементов. Сразу после этого я снова вызываю QVector::reserve для 42 элементов. Что я заметил, так это то, что после этого у процесса все еще есть память, выделенная для этих 420000 элементов. Почему память не освобождается, когда я уменьшаю размер QVector до 42?

Возьмите следующий код:

#include <QCoreApplication>
#include <QVector>
#include <QDebug>

typedef QVector<QPointF> PointVec;
typedef QList<PointVec*> PointVecList;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "Processing...";

    PointVecList list;

    for (int i = 0; i < 4200; i++) {
        PointVec *v = new PointVec();

        v->reserve(420000);
        v->resize(420000);

        v->reserve(42);
        v->resize(42);

        list.append(v);
    }

    qDebug() << "End of processing...";

    return a.exec();
}

Этот код дает сбой, вызывая исключение std::bad_aloc (Unhandled exception at 0x7729C41F in QtConsoleApplication1.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0034F5E8.) в 32-битной системе (поскольку система не поддерживает много оперативной памяти для одного процесса).

Однако, если я прокомментирую строки v->reserve(420000); и v->resize(420000);, все будет работать нормально. Вот как я заметил, что если я вызываю v->reserve(42); и v->resize(42); (после предварительного резервирования/изменения размера вектора до 420000 элементов), превышение памяти не освобождается.

Я также заметил, что std::vector ведет себя точно так же.

Можно ли заставить Qt также освобождать память? Если нет, то можно ли самому, вручную, как-то освободить?


person Jacob Krieg    schedule 26.01.2018    source источник
comment
почему вы ожидаете, что reserve(42) освободит память? Просто нужно убедиться, что места достаточно, а не то, что места не более чем достаточно.   -  person 463035818_is_not_a_number    schedule 26.01.2018
comment
Вы можете попробовать std::vector::shrink_to_fit, но это ни к чему не обязывает.   -  person François Andrieux    schedule 26.01.2018
comment
@ tobi303, другими словами, я хочу зарезервировать достаточно памяти, чтобы выполнить некоторые операции с вектором. после того, как я совершу операции, я точно знаю, сколько памяти нужно вектору, поэтому мне нужно, чтобы процесс использовал минимальное использование памяти... любые намеки на то, как я могу это сделать?   -  person Jacob Krieg    schedule 26.01.2018
comment
@FrançoisAndrieux, что ты имеешь в виду под it's non-binding?   -  person Jacob Krieg    schedule 26.01.2018
comment
a vector действительно управляет своей памятью для вас (в значительной степени), если вам нужен полный контроль, я бы прибегнул к динамически выделяемому c-массиву   -  person 463035818_is_not_a_number    schedule 26.01.2018
comment
... или, может быть, это можно сделать с помощью специального распределителя, но я просто предполагаю, что сам никогда не использовал его   -  person 463035818_is_not_a_number    schedule 26.01.2018
comment
@JacobKrieg Вызов shrink_to_fit может изменить capacity на size, может уменьшить capacity, если оно больше size, или вообще не изменить capacity. Дело за реализацией.   -  person François Andrieux    schedule 26.01.2018
comment
Если у вас все равно недостаточно свободной памяти для этого распределения, почему вы беспокоитесь об ее освобождении?   -  person Justin Randall    schedule 26.01.2018
comment
Вы, кажется, путаете .reserve() и .resize(). .reserve() никогда ничего не сжимает, он просто гарантирует, что пространство предварительно выделено как минимум для такого количества элементов, сколько вы reserve.   -  person Jesper Juhl    schedule 26.01.2018
comment
@JesperJuhl Но действительно ли изменение размера освобождает память, когда количество элементов для изменения размера меньше размера вектора? Из документации Qt QVector: If size is less than the current size, elements are removed from the end.. Итак, если он удаляет с конца, почему память не освобождается? Если его элементы размещены в стеке, память должна освободиться, верно?... почему память не освобождается?   -  person Jacob Krieg    schedule 26.01.2018
comment
@Jacob Krieg Смотрите мой ответ.   -  person Jesper Juhl    schedule 26.01.2018


Ответы (1)


Если нет фактического нехватки памяти, для базовой библиотеки имеет смысл не выполнять работу по фактическому освобождению выделенной памяти обратно в ОС, а вместо этого хранить ее и использовать для удовлетворения новых выделений (без переключения контекста, чтобы получить ее из ядро), которые вы, скорее всего, скоро сделаете.

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

Итак, причина в эффективности. Фактическое освобождение памяти сопряжено с затратами, и нет причин платить за это до тех пор, пока вам действительно это не понадобится — чего во многих случаях никогда не будет.

person Jesper Juhl    schedule 26.01.2018