Обработка вложенных указателей QVector

Я унаследовал существенный проект Qt5, где накопительная утечка памяти становится серьезной проблемой. (Да, утечка памяти редко допускается, но с реальным бюджетом и временными ограничениями...).

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

QVector < QVector <Voxel *> > cVoxel;

Когда изображение читается из файла, cVoxel инициализируется с помощью QVector.resize(0) ,

cVoxel.resize(0);

Когда изображение, сохраненное в файл, открывается, локальный Voxel указатель создан и помещен в конец cVoxel , один раз для каждого пикселя, так что цикл за все строки и столбцы:

for (iRow = 0; iRow < nRows; ++iRow)
{
   for (iCol = 0; iCol < nCols; ++iCol)
   {
      Voxel *v = new Voxel;
      cVoxel[iRow].push_back(v);
      // Code for reading data into cVoxel removed here
      ...
   }
}

Благодаря приведенным ниже полезным комментариям, я теперь добился некоторого успеха в уменьшении использования памяти в диспетчере задач Windows, вложив разрушение cVoxel QVector в мой CTOR. По линии:

for (iRow = 0; iRow < nRows; iRow++)
{
    for (iCol = 0; iCol < nCols; iCol++)
    {
        delete cVoxel[iRow][iCol];
    }
}

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

  • Я смотрел на утечки памяти в Voxel сам по себе, но там нет ничего очевидного.
  • Мои исследования показывают, что просмотр диспетчера задач Windows на предмет потребления памяти не совсем надежен (Win7 не является ОС реального времени...), но если открытие файла увеличивает потребление памяти приложением с 16 до 81,5 млн, то, несомненно, должно быть некоторое уменьшение памяти, если выделенная память в cVoxel успешно выпущен? Если я продолжу открывать и закрывать изображения, потребление памяти приложением будет увеличиваться на том же этапе. Он никогда не уменьшается после закрытия всех / всех открытых изображений.
  • Сейчас нет попыток освободить память, назначенную (используя новый оператор) cVoxel, Я попробовал несколько подходов (и прочитал, чтобы узнать больше), но пока что немного повезло.
  • QVector отлично справляется со своей собственной обработкой памяти, но я застрял с этой настройкой гнезда QVector и просто полагаясь на squeeze(), resize() или аналогичные QVector, будет только утечка памяти (что уже имеет место для других Переменные в проекте. Я запустил проект с помощью Visual Leak Detector, поэтому у меня есть идея, кто из них является серьезным, а кто - мелкой рыбой)

----РЕДАКТИРОВАТЬ ----

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

Я отредактировал in-line выше, чтобы (надеюсь) сделать этот пост более понятным, и удалил мое лучшее дело, так как оно не повлияло на утечку памяти. Значительное изменение выше - это (2) краткие абзацы, выделенные курсивом.

Мне также нужно исследовать предположение, связанное с полиморфизмом @richardcitter (sp?).

--- EDIT3 ---

Убрал Edit2, разместил этот (новый) вопрос отдельно здесь.

Кроме того, я уверен, что ответ ниже должен исправить этот вопрос - мне просто нужно выяснить, как использовать qvector.resize() или найти обходной путь к этому.

2 ответа

Решение

@SomeProgrammerDude: Вы дали мне 9/10 к решению. Я не знаю, должен ли я отредактировать ваш ответ или использовать это, поэтому модераторы должны редактировать соответственно.

Как обрисовано в общих чертах в сообщении SO, в конце концов я решил отказаться от умных указателей. Вышеупомянутое решение ввело (для меня) проблему компилятора, пытающегося ссылаться на удаленную функцию. В противном случае это правильно с парой модификаций:

QVector < QVector <Voxel *> > cVoxel;

Инициализация:

cVoxel.resize(0);

Назначение памяти:

{
   for (int i = 0; i < rows; ++i)
   {
      cVoxel.push_back( QVector <Voxel *> () );
      for (int j = 0 ; j < cols ; ++j)
      {
         Voxel *v = new Voxel;
         cVoxel[i].push_back(v);
      }
   }
}

Наконец DTOR освобождает память:

   int iRow, iCol;
   for (iRow = 0; iRow < rows; iRow++)
   {
      for (iCol = 0; iCol < cols; iCol++)
      {
           delete cVoxel[iRow][iCol];
      }
   }

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

Чтобы решить неопределенное поведение и должным образом убедиться, что вам не нужно делать никаких дополнительных выделений, вы можете предварительно выделить количество элементов в векторах. Вы уже делаете это, когда звоните resize(0), но вместо того, чтобы установить нужный вам размер, вы устанавливаете нулевой размер, вы делаете вектор пустым.

Я бы предложил что-то вроде этого:

Первое использование std::unique_ptr как предложил Ричард Криттен:

QVector < QVector < std::unique_ptr <Voxel> > > cVoxel;

Если у Qt есть собственный уникальный тип указателя, вы можете использовать его вместо этого.

Затем, когда вы создаете, вы используете resize чтобы установить фактический размер векторов:

cVoxel.resize(nRows);

Тогда вы можете использовать простые индексы в векторе. Установите размер для внутренних векторов:

for (iRow = 0; iRow < nRows; ++iRow)
{
   cVoxel[iRow].resize(nCols);  // Resize to the number of columns

   for (iCol = 0; iCol < nCols; ++iCol)
   {
      cVoxel[iRow][iCol].reset(new Voxel);  // Create the actual Voxel object

      // Code for reading data into cVoxel here
      ...
   }
}

Так как вы используете std::unique_ptr (или эквивалент Qt) памяти, управляемой std::unique_ptr объект будет автоматически освобожден после уничтожения объекта. Так что нет больше утечек памяти, когда cVoxel вектор выходит за рамки или иным образом разрушается, так что ваш Voxel объекты будут.

Другие вопросы по тегам