C++ с D3DX9 - Размерът на паметта продължава да се увеличава със скорост от 10 MB/sec - Защо?

Работя върху 3D двигател като училищен проект. Инсталирах виртуален детектор за течове, за да се отърва от течове на памет (и той проработи, тъй като вече не получавам нито едно от тези изхвърляния). Наскоро случайно оставих приложението ми да работи за 5 минути... И компютърът ми стана адски бавен. Проследих проблема, като коментирах редове и други подобни, но не мога да разбера защо C++ не освобождава моята изчистена памет, докато не затворя приложението.

ПРОБЛЕМ: „Вътрешно“ изтичане на памет, изглежда, че C++ изтрива нещо само след като приложението се затвори

КОД: Моят код за изобразяване (в pastebin Yz79Ck0b)

ЗАБЕЛЕЖКИ: Знам, че не трябва да създавам нов Mesh всеки път, но това не би трябвало да създава този проблем, нали? Моята IDE е Visual Studio 2008 и използвам проект WIN32. Когато извадя текстурата и модела, имам 0 байта растеж на паметта.


person Pimgd    schedule 13.12.2010    source източник
comment
Replace изглежда, че C++ изтрива само от моя код само изтрива. Каквото и програмата ви да не пусне, докато върви, операционната система ще пусне, когато процесът (програмата) приключи.   -  person André Caron    schedule 13.12.2010


Отговори (3)


Както казва Sanjit, трябва да използвате delete[] за изтриване на масиви - и както казва DeadMG, RAII контейнерът е най-добрият практически начин да не объркате освобождаването на вашия ресурс.

Въпреки това, въпреки че не е веднага очевидно от документите, очевидно всички ресурси на Direct3d (включително IDirect3d9Texture, който D3DXCreateTextureFromFile създава) наследява от IUnknown - те са COM обекти, с други думи. Трябва да .Release() COM обекти, когато приключите с използването им:

for (int i=0; i<len; i++)
  if (m_Texture[i] != NULL)
    m_Texture[i]->Release();//decrement COM refcount to permit releasing the resource
delete[] m_Texture;
delete[] m_Material;

Вероятно искате да придобиете навик да опаковате тази повтаряща се логика в удобен RAII контейнер. ATL има вградено такова нещо, вижте MSDN-docs на CComPtr. Предупреждение: Никога не съм го използвал преди, но нещо подобно е много добра идея, ако възнамерявате да напишете нещо по-голямо от приложение за играчки, използвайки COM.

person Eamon Nerbonne    schedule 13.12.2010
comment
+1 за посочване, че COM обектите трябва да бъдат освободени с Release(). - person Sanjit Saluja; 13.12.2010
comment
Благодаря отново, момчета - имам един последен въпрос - изглежда трупам байтове памет тук и там - това нормално ли е? - person Pimgd; 13.12.2010
comment
@Pimgd: DirectX е сериозна библиотека. Използва сериозно количество памет. Нормално е дори леките D3D приложения да използват доста малко памет. - person Puppy; 13.12.2010

m_Material е масив, имате нужда от [] с оператора за изтриване:

delete[] m_Material;

Освен това изглежда, че m_Texture е масив от указатели, които са нови. D3DXCreateTextureFromFileA(m_Device, d3dxMaterials[i].pTextureFilename, &m_Texture[i])

Правилният начин за изтриване на масив от динамично разпределени указатели е:

    for (int i=0; i<len; i++)
    {
      // first delete memory for each index
      if (m_Texture[i] != NULL)
      {
        delete m_Texture[i];
      }
    }

    // then delete the array
    delete[] m_Texture;
person Sanjit Saluja    schedule 13.12.2010
comment
Имате същия бъг с m_Texture. - person Sanjit Saluja; 13.12.2010
comment
Правилният начин за изтриване на масив от динамично разпределени указатели е с RAII. - person Puppy; 13.12.2010
comment
Моля, не бъркайте публикацията ми за почистване на масиви с модела за проектиране RAII. - person Sanjit Saluja; 13.12.2010
comment
@Sanjit: Не съм. Това е проблема. - person Puppy; 13.12.2010
comment
@DeadMG: Санджит е прав, new[] трябва да се съчетае с delete[]. Опаковането на това в клас RAII би било още по-добро и замяната на ръчното управление на паметта с std::vector още по-добре, но нищо от това не обезсилва гледната точка на Sanjit. - person Ben Voigt; 13.12.2010
comment
@DeadMG: диагнозата е правилна. RAII е едно възможно решение, но не е единственото валидно. - person André Caron; 13.12.2010
comment
Вашата публикация има разумен шанс да бъде правилна, но по принцип не можете просто да изтриете паметта, разпределена с персонализирани функции - трябва да използвате подходящата функция за изтриване. За съжаление, API не уточнява кое би било това - blech (това е повтарящ се проблем на MSDN - в документите на API обикновено липсва основна, необходима информация). Тъй като текстурите се разпределят потенциално във видео паметта, наистина е напълно възможно наистина да се нуждаете от различна функция за изтриване. Не знам. - person Eamon Nerbonne; 13.12.2010
comment
Правилният начин за изчистване на указателите беше използването на delete[] и m_Texture[i]-›Release(); (и не изтривайте m_Texture[i]). Благодаря момчета! - person Pimgd; 13.12.2010

Трябва да използвате RAII, за да обработвате всеки ресурс, който се нуждае от освобождаване, а НЕ да ги освобождавате ръчно.

template<typename T> class self_release_ptr {
    T* ptr;
public:
    self_release_ptr(T* newptr) : ptr(newptr) {}
    self_release_ptr() : ptr(0) {}
    ~self_release_ptr() { if (ptr) ptr->Release(); }
    // etc
};
std::vector<self_release_ptr<texture_type>> m_Texture;

Мога да бъда по-конкретен, но трябва да видя дефиницията на класовете.

person Puppy    schedule 13.12.2010
comment
Контейнерът RAII, който дефинирате, оставя опасни битове на // etc - или препратете към съществуващ, или го попълнете (с конструктори за присвояване и копиране); този може да се взриви в лицата на хората. - person Eamon Nerbonne; 13.12.2010
comment
@Eamon: Няма да пиша цял интелигентен показалец за него. Моята работа е да му дам идеята, а не да я реализирам. - person Puppy; 13.12.2010
comment
Разбирам, но е наистина лесно да прецакате внедряването на интелигентни показалци, ако не разбирате напълно детайлите на C++ RAII модела - оставянето на неприятните части на // etc означава да го помолите да се простреля в крака . Ако не искате да го прилагате - недейте! Той трябва или да използва съществуващ интелигентен указател, или пълен пример. Ако премахнете своя примерен код или още по-добре изброите различните необходими съставки, вашият отговор не може да бъде разбран погрешно. (За да бъде ясно: гласувах против, защото съм правил такава грешка в миналото). - person Eamon Nerbonne; 13.12.2010