locked
Multiple SwapChainBackgroundPanel objects lead to memory leak

    General discussion

  • I am making a game app which has two Pages:

    Page1: For level selection (fully XAML, C#)

    Page2: For the game (SwapChainBackgroundPanel, Logic: C#, DirectX: C++)

    I switch between them using

    Window.Current.Content = MyPage1;

    or

    Window.Current.Content = new Page2(...);

    The problem is that when switching from Page 2 back to Page 1 the DirectX memory seems not to be released.

    Using ProcessExplorer I can see that the GPU memory stays the same. And If I create  new Page2's, then the GPU memory increases further and further and further.

    I am completely sure that it has to do with DirectX because if I comment out the DirectX creation and initialisation in Page2, then (I have a black screen, of course, and) the memory does not increase.

    So, there seems some reference to the old DirectX objects in Page 2 which are not released. What must be done to release DirectX resources?

    Internally, my DirectX class seems to work properly. Since if I bring the app into the snapped view I can see that the GPU memory decreases from 45 MB to 17 MB. (so the resources seem to be released properly). And if I create 10 DirectX objects and initialise them 10 times in Page2, then the 9 "old" DirectX objects do not waste memory.

    I think the problem is that I do not tell the system that the SwapChainBackgroundPanel and the DirectX resources should be completely released from the app when switching from Page2 to Page1.



    Monday, March 18, 2013 12:44 PM

All replies

  • Are you using Microsoft::WRL::ComPtr<T> for all the COM-based DirectX objects? COM is reference counted so if you aren't using ComPtr (or a similar smart pointer) then you may have problems with failing to properly release all objects. Further, if you are using any lambdas (especially for event handlers), you could easily be creating circular references (which will result in memory leaks).

    If you are leaking objects in Direct3D, the debug layer (see http://msdn.microsoft.com/en-us/library/windows/desktop/ff476881.aspx#Debug and http://msdn.microsoft.com/en-us/library/windows/desktop/ff476366(v=vs.85).aspx ) should help you to track them down.


    XNA/DirectX MVP | Website | Blog | @mikebmcl

    Monday, March 18, 2013 2:32 PM
  • Thank you MikeBMcL, for your reply!

    > Are you using Microsoft::WRL::ComPtr<T> for all the COM-based DirectX objects?

    Yes, I am using ComPtr. And as I wrote: If I initialize 10 times the DirectX stuff, it does not use more than 1 time of the normal memory.

    > Further, if you are using any lambdas (especially for event handlers), you
    > could easily be creating circular references (which will result in memory leaks).

    In the C++ part, I do not use events or anything. In the C# Page2 class, I use events, but I do unsubscribe at the end. And I know that the Page2 instances are garbage collected: Since if I have a dummy byte array of 500 MB as member of a Page 2 instance, I can see that these 500 MB are released if I switch from Page 2 to Page 1. So the objectes are really realeased and garbage collected. 

    I have noticed a interesting fact: If I comment out this code:

            DX::ThrowIfFailed(
                dxRootPanelAsSwapChainBackgroundPanel->SetSwapChain(m_swapChain.Get())
                );

    the screen, of course, stays black, but all DirectX objects are allocated (which I can see from ProcessExplorer). When I then switch from Page 2 to Page 1, everything is released properly!

    So, it seems to have to do with the connection between SwapChainBackgroundPanel and DirectX.

    Is there something like UnSetSwapChain?

     


    • Edited by eikuh Monday, March 18, 2013 2:44 PM
    Monday, March 18, 2013 2:43 PM
  • You can pass nullptr to SetSwapChain when you navigate away from the page just so long as you set it back to the right value when you navigate to it again.


    XNA/DirectX MVP | Website | Blog | @mikebmcl

    Monday, March 18, 2013 3:50 PM
  • I already tried to pass nullptr to SetSwapChain. But this does not resolve the increasing memory problem, unfortunately...
    Monday, March 18, 2013 4:02 PM
  • Now, for testing, I switched from Page 1 to Page 2 and back inside a while-loop. (waiting 200 ms between each switch). After 295 switched, the app crashed with an "out of memory" exception. This is a screenshot from Process Explorer. The red lines shows the crash.

    Monday, March 18, 2013 4:19 PM
  • Another interesting finding:

    If I bring the app to background (while it is still running, i.e. creating new DirectX resources and switching between Page 1 and Page 2 (it is not suspended because it is run from Visual Studio in Debug mode)), the system "recoveres", see image below. When the app is brought back to foreground, the memory usage increases again:

    Monday, March 18, 2013 4:39 PM
  • How are you mixing C# and C++?

    XNA/DirectX MVP | Website | Blog | @mikebmcl

    Monday, March 18, 2013 11:34 PM
  • > How are you mixing C# and C++?

    The DirectX part is a WinRT component written in C++.

    I can call methods of this DirectX component (like initialize, drawCircle etc.) from C#.

    The DirectX C++ part is based on the code from the "DirectX postcard sample" (among the Win 8 samples from Microsoft).

    Currently I am thinking about using only one DirectX page. I would have to change my code quite a bit. But then I would not have to create new objects again and again. So, this would not be a solution of the actual problem, but this would be a way round it.

    But if there would be a real solution, I would be very glad, of course.

    @ Microsoft: What is the official way to switch between multiple Pages with SwapChainBackgroundPanel?
    • Edited by eikuh Tuesday, March 19, 2013 9:43 AM
    Tuesday, March 19, 2013 9:42 AM
  • If you can create a small repro solution (or are willing to share the current solution) and upload it to SkyDrive (or something similar), I'd be happy to look at it and try to figure out what's going wrong. Somehow there's a reference that isn't being released but there's no simple way to track it down.

    Another option would be to have your C++ component expose a public method that will release all of the DirectX resources. Like you said, it's releasing everything when it resizes a page for snap. So if you separated out the release of all the resources from the creation and then called the release method when you go back to page 1 it might solve the problem.


    XNA/DirectX MVP | Website | Blog | @mikebmcl

    Tuesday, March 19, 2013 5:42 PM
  • Ok, now I have created a tiny example app:

    http://sdrv.ms/11dS2CB

    The app is really simple. It consists of two Pages: MainPage and Page2.

    On Page2, there is a SwapChainBackgroundPanel.

    Use the space bar to toggle between the pages. (and use two fingers to be faster).

    Depending on your fingers, you will have an Exception within one minute. Watch the memory increasing in Process Explorer.

    Wednesday, March 20, 2013 8:48 AM
  • I should've caught this earlier, sorry. The sample app is violating one of the DirectX - XAML interop rules (see "SwapChainBackgroundPanel and gaming" on http://msdn.microsoft.com/en-us/library/hh825871.aspx ), namely that the SwapChainBackgroundPanel is not the root element of the app. (As a byproduct it is also violating the rule that there must be only one SwapChainBackgroundPanel instance per app since it creates a new one every time you go to page 2).

    To the best of my knowledge, the SwapChainBackgroundPanel-based interop isn't able to support multiple pages directly. Instead what you would do is create each of your desired XAML pages as a UserControl (or some other Control-based XAML component) and then on the one main page (the actual XAML page with the SwapChainBackgroundPanel as its root element), you would set the child element of the SwapChainBackgroundPanel to whichever of the user controls you wanted based on navigation within the app. It'll require a redesign as you suspected in an earlier post. But once you do that, your app memory should stay stable while still giving you XAML - DirectX interop and the ability to design XAML using, e.g., Blend for Visual Studio or the Visual Studio XAML Designer (since either can edit a UserControl or other Control-based control just fine).

    Sorry there isn't a simpler solution. I tried several ways of trying to force the app to release internal resources, but the interop just isn't built to support that currently. Hopefully they'll consider adding that scenario in the future since it's (to me) a cleaner, clearer, more familiar way of working with XAML. But I have some sense of how complex it would be so it's not surprising to me that it's not something that's possible right now.


    XNA/DirectX MVP | Website | Blog | @mikebmcl

    Wednesday, March 20, 2013 11:31 PM
  • First of all, thank you, MikeBMcL for all the time you have spent and are spending to help me!

    You mentioned the rules:

    > There is only one SwapChainBackgroundPanel instance per app.

    You understand: You can only create one instance and then must keep it.

    I understand: One cannot have more than one instance at the same time.

    > The SwapChainBackgroundPanel must be the root XAML element of the app.

    You (maybe) understand: The SwapChainBackgroundPanel must be the "super-root" element.

    I understand: The SwapChainBackgroundPanel must be the root element of the _Visual_ tree.

    If we take a look at the Postcard example from Microsoft; there the SwapChainBackgroundPanel is only the root element in the visual sense (like I understood it):

    <Page
        x:Class="Postcard.MainPage"
        ...
        >
        
        <SwapChainBackgroundPanel x:Name="DXSwapChainPanel">
        
        ...
    
        </SwapChainBackgroundPanel>
    </Page>

    So, ok, I will have to redesign my app (it does not matter if I violated the rules or if there is a bug in Windows).

    But just for curiosity: I would like to know from Microsoft how the rules are really meant. I will mark your reply as answer, but I will start a new question in the forum. 

    Edit: I just saw that I cannot propose your reply as answer because Jesse Jiang has downgraded this thread from question to discussion... So, I can only mark your reply as helpful...
    • Edited by eikuh Thursday, March 21, 2013 7:05 AM
    Thursday, March 21, 2013 7:02 AM