О Том, Как Текла Память И Я Не Мог Понять Почему

Здравствуйте, уважаемые хабра-люди.

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

Мы поговорим о DirectX и, как мне показалось, странных утечках памяти.



Как я создал себе проблему?

Я решил использовать DirectX для отображения содержимого страниц.

Идея была проста: сначала я создаю 2D-текстуру с текстом, а затем отображаю 3D-модель, используя заранее подготовленные текстуры.

Это дает мне возможность создавать 3D-анимацию переворачивания страниц.

Что-то вроде этого:

О том, как текла память и я не мог понять почему

Когда приложение было выпущено в магазин, я ожидал всеобщего восхищения.

Но не тут-то было.

Пользователи были недовольны.

Анализ ситуации показал, что память утекает. И оно течет очень хорошо.

Но почему? Я долго не мог этого понять.

Учитывая, что приложения в Windows 8.1 и Windows Phone 8.1 не выгружаются полностью при «закрытии», утечки памяти накапливаются.

Сам процесс поиска утечки оказался совсем не интересным.

Но результат мне показался странным.



Что мне показалось странным?



Освобождение ресурсов рендер-таргета (не знаю как перевести) и буфера глубины

Для отображения одного кадра 3D-сцены используются следующие объекты:
  
  
  
  
  
  
  
  
   

Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_renderTargetView; Microsoft::WRL::ComPtr<ID3D11DepthStencilView> m_depthStencilView;

Далее где-то в методе отображения сцены мы будем использовать такой код:

ID3D11RenderTargetView *const targets[1] = { m_renderTargetView.Get() }; m_d3dContext->OMSetRenderTargets(1, targets, m_depthStencilView.Get());

Ресурсы необходимо высвободить.

И здесь кроется одна из проблем, которая привела к созданию этого поста.

Просто пиши:

m_renderTargetView = nullptr; m_depthStencilView = nullptr;

недостаточно.

m_d3dContext все еще содержит ссылки на цель рендеринга и буфер глубины где-то внутри.

Те.

Нам нужно указать нашему контексту небытие как цель.



m_d3dContext->OMSetRenderTargets(0, nullptr, nullptr);

Беда в том, что мы получим утечку памяти, если сделаем это так:

m_d3dContext->OMSetRenderTargets(0, nullptr, nullptr); m_renderTargetView = nullptr; m_depthStencilView = nullptr;

Чтобы исправить ситуацию, достаточно изменить порядок инструкций:

m_renderTargetView = nullptr; m_depthStencilView = nullptr; m_d3dContext->OMSetRenderTargets(0, nullptr, nullptr);

Это первая «странность», которую я не понимаю.

Буду рад, если кто-нибудь подскажет, почему так происходит.

Освобождение ресурсов текстур

Вторая «странность» связана с текстурами.

Вернее, с шейдерными ресурсами.

Дело в том, что если мы сделаем это так:

Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> texture = .

m_d3dContext->PSSetShaderResources(0, 1, &texture);

Они должны сделать это следующим образом:

ID3D11ShaderResourceView* empty = NULL; d3dContext->PSSetShaderResources(0, 1, &empty);

В противном случае текстура не выйдет, даже если вы ее «удалите».



texture = nullptr;

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

В принципе, после осознания первой «странности», вторая уже не кажется таковой.

И все же мне это не показалось очевидным.

P.S.: Сейчас проблема с утечкой памяти устранена и гнев пользователей постепенно меняется на милость.

Теги: #DirectX #C++ #утечки памяти #Разработка для Windows Phone #Разработка для Windows

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.