Уменьшить размер std :: vector, чтобы он соответствовал фактическим данным для экономии памяти? vec.swap () не работает в MSVC? - PullRequest
4 голосов
/ 23 февраля 2012

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

Так что я хочу уменьшить их возможности для экономии памяти. типичным способом является использование метода vector.swap (), как описано в этот вопрос :

 std::vector<T> tmp(v);    // copy elements into a temporary vector
           v.swap(tmp);              // swap internal vector data

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

Почему это так? UPDATE " Я использую VS 2008, и я добавил несколько строк для вывода текущей емкости во время выполнения. Как видно из приведенного ниже кода и его результатов, vec.capacity сократился до 10 после перестановки, но это не отражается в диспетчере задач.

Или, может быть, как сказал @ Адам Розенфилд, это изменение не вернуло освободившееся пространство для ОС? Или я не должен использовать диспетчер задач, чтобы посмотреть его использование памяти? Я надеюсь, что эта операция swap () может иметь такой же эффект, как и delete pointer_to_a_big_vec, который непосредственно освободит память.

Мой тестовый образец здесь:

void vecMemoryTest()
{
  vector<int> vec;

  //make it big!
  for(int i = 0; i <= 100000; i++){vec.push_back(i);}
  for(int i = 0; i <= 100000; i++){vec.push_back(i);}

  cout << "Before .resize() : " << vec.capacity() << endl;

  //OK now I only need the first 10 elements
  vec.resize(10);   

  cout << "After .resize() : " << vec.capacity() << endl;

  //So try to free other spaces
  vector<int> tmp(vec.begin(), vec.end());



  vec.swap(tmp);    // now should free wasted capacity
            // But in fact it doesn't

  cout << "After .swap() : " << vec.capacity() << endl;
}

и вывод:

До .resize (): 207382 После .resize (): 207382 После .swap (): 10

Ответы [ 5 ]

7 голосов
/ 24 февраля 2012

Проверьте capacity() вектора.Скорее всего, вы обнаружите, что вектор фактически уменьшил использование памяти.Вероятно, вы видите, что реализация malloc() не освобождает память обратно в ОС.

3 голосов
/ 24 февраля 2012

Счетчик рабочего набора учитывает только зафиксированное виртуальное адресное пространство. Он не учитывает, как его используют отдельные пользователи этого адресного пространства.

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

Еще лучшим тестом было бы изменить vecMemoryTest(), чтобы снова выделить огромный vector того же размера, а затем уничтожить его. Если рабочий набор остается (в основном) одинаковым, вы знаете, что правильно сократили оригинал vector.

1 голос
/ 24 февраля 2012

Вы работаете с Visual Studio 2010? Если так, то он поддерживает новый метод C ++ 0x для вектора, shrink_to_fit. См MSDN ссылка .

1 голос
/ 24 февраля 2012

C ++ 11 предоставляет std::vector::shrink_to_fit, что вы можете попробовать. Эта функция запрашивает, чтобы емкость вектора была уменьшена до размера данных, которые он содержит. Однако , реализация не привязана к этому запросу, поэтому вам придется проверить, как он себя ведет.

Если вы хотите избежать «блочных» резервирований, вам придется изучить специализированную реализацию стандартной библиотеки; например, те, которые используются для разработки игр, могут обеспечить необходимую вам функциональность.

Важно помнить, что когда вы запрашиваете память с помощью new, операционная система часто дает вам больше памяти, чем вы запрашивали. Это может оказать некоторое влияние на то, что вы видите.

1 голос
/ 24 февраля 2012

Я не смотрел на реализацию, но возможно, что конструктор копирования для vector также копирует емкость.

Используйте форму итератора для создания нового временного объекта:

vector<int> tmp(vec.begin(), vec.end());
vec.swap(tmp);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...