📜 ⬆️ ⬇️

About how the memory flowed, but I could not understand why

Hello, dear Habracheloveki.

In this short post, I want to share with you some moments that I encountered while developing one of my applications (Windows reader). It's about DirectX and, as it seemed to me, strange memory leaks.

How did I make myself a problem?


To display the content of the pages I decided to use DirectX. The idea was simple: first I create a 2D texture with text, and then I display a 3D model using previously prepared textures. This gives me the ability to animate 3D page turning.
')
Something like this:



At the time of the release of the application in the store, I expected universal admiration. But it was not there. Users were unhappy. An analysis of the situation showed that memory is flowing. And it flows very well. But why? This I could not understand for a long time.
Considering the fact that applications in Windows 8.1 and Windows Phone 8.1 are not completely unloaded when “closing”, memory leaks accumulated.

The leak detection process itself was not at all interesting. But the result seemed strange to me.

What seemed strange to me?


Freeing the render-target resources (I don’t know how to translate) and the depth buffer


The following objects are used to display one frame of a 3D scene:

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

Further, somewhere in the scene display method, we will use something like this code:

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

Resources must be freed. And here lies one of the problems that caused this post.
Just write like this:

 m_renderTargetView = nullptr; m_depthStencilView = nullptr; 

not enough. At m_d3dContext somewhere inside there are links to the render-target and the depth buffer.
Those. it is necessary for our context to specify nothing as a goal.

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

The trouble is that we get a memory leak if we do this:

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

To correct the situation, it is enough to change the order of instructions:

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

This is the first "oddity" that I do not understand. I will be glad if someone tells why this is happening.

Freeing texture resources


The second "oddity" is associated with textures. Or rather with shader resources.
The fact is that if we do this:

 Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> texture = ... m_d3dContext->PSSetShaderResources(0, 1, &texture); 

That should do and so:

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

Otherwise, the texture will not be released, even if you "delete" it.

 texture = nullptr; 

In other words, before removing (release) shader resources, they must be released (unbind).

In principle, after the realization of the first “strangeness”, the second one no longer seems so.
And yet, it seemed to me not obvious.

PS: Now the problem with memory leak is fixed and the anger of users is gradually changing to mercy.

Source: https://habr.com/ru/post/242893/


All Articles