locked
Pages not getting garbage collected on WP 8.1 app.

    Question

  • I am developing an application which uses MediaElement class for playing video. But when navigated between Pages and doing memory profiling using Visual Studio Performance and Diagnostics, I observed even though the page reference is not there in the managed Heap the memory is not going down/not getting GC. On further digging and profiling the native heap the page frame is not getting released/collected from native space though there is no active reference in Managed heap. This causes an increase in some residual memory every time I navigate to a Page.

    To validate the behaviour I created a sample application having 2 pages:

    a)Page 1 will be having a button with which we can navigate to Page 2.

    b)On button click Page 2 will be launched and Page 1 will be cleared from backstack (in onNavigateFrom of Page 1 ->  Frame.BackStack.Clear(); )

    c) From Page 2 if back button is pressed Page 1 will be launched again and Page 2 will be cleared. The process repeats .

    Observation: Every time I navigate from one page o another memory keeps on increasing an never gets collected.

    Note: same behaviour observed when backstack is not cleared and used default back navigation.

    On exploring further found Windows holds the last three page frames in memory for caching purpose and as a workaround do a force GC in onNavigateTo  : 

     GC.Collect();
     GC.WaitForPendingFinalizers();

    This solves the problem a bit. Memory will increase for sometime and then remains constant at a certain point after which there is no memory increase on navigation.

    Is this the Windows behaviour? Has someone encountered similar problems? Is there any proper fix for this behaviour. It would be really helpful if somebody can provide a proper solution.

    Thanks,

    Wednesday, April 8, 2015 2:35 PM

Answers

  • It is possible that the Pages are large enough (over 85K) in object size that they are not placed on the regular heap, but the LOH instead? That may prevent the GC.Collect from collecting the page until there's memory pressure. According to MSDN, you can try this code to force a LOH GC:

    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
    GC.Collect();      
    


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, April 9, 2015 12:25 PM
    Moderator

All replies

  • It is possible that the Pages are large enough (over 85K) in object size that they are not placed on the regular heap, but the LOH instead? That may prevent the GC.Collect from collecting the page until there's memory pressure. According to MSDN, you can try this code to force a LOH GC:

    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
    GC.Collect();      
    


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, April 9, 2015 12:25 PM
    Moderator
  • Hi Jose,

    GC will work periodically, there is no specific time that GC will run, GC will keep on running in the gen 0 (short lived objects like temp variable) , and gen 2 objects will be cleared when the physical memory is low etc.

    When GC runs in gen 2 it is called complete garbage collection.

    In your case GC is running in gen 0 and your memory consumption is still high. But GC will run  after certian period of time and it will clear all your objects in Gen 2.

    It is not your problem , this is how GC works. You dont need to fix CLR will initaitate GC when it actually wants.

    Please mark this as answer if it answers your question.



    Purushothama V S


    Thursday, April 9, 2015 2:08 PM
  • Hi Matt,

    Thanks for the response. After adding the code snippet and when MediaElement source is set to null, the memory is getting freed up when navigating between pages. But when I set the MediaElement source (using setSource(fileStream) not all the memory is getting collected and some residual memory remains.

    For eg:

    I have a sample app having 2 pages. First page has a "Navigate" button, which on pressing launches a second page having 4 media elements arranged in a grid. 4 different video file streams( from sd card) will be read and set to MediaElement.

    In OnNavigatedTo of each page I will be doing a force GC as:

      protected override  void OnNavigatedTo(NavigationEventArgs e)
            {
    
                GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
                GC.Collect();
                GC.WaitForPendingFinalizers();
             }

    In OnNavigatedFrom of each page I will be clearing the stack : So when I move from Page 1 to Page 2, page 1 will be cleared from the stack, an explicit GC will be done on Page 2 launch. When back button is pressed from page 2, page 2 will be cleared from stack and page 1 will be again launched.

     protected override void OnNavigatedFrom(NavigationEventArgs e)
            {
                  Frame.BackStack.Clear();
            }


    The app behaviour under different scenarios are as follows:

    1)When MediaElement Source is not set (null).

     a) Page 1 is launched, say now the memory is 16MB.

     b) On "Navigate" button click Page 2 is launched.

    c)The LOH explicit GC will get triggered and memory will get reduced to 14 MB.

    d) MediaElement source is not set in page 2:

    Commented this part of the code to not set any source.

    //_mediaElementList.ElementAt(_index).SetSource(stream, file.ContentType);

    e) Now the page will be consisting of 4 media element's but with no videos playing (source).

    f)If I press back Page 2 all the 4 MediaElement Source will be set to null, Page 2 will be cleared from the stack and Page 1 will be loaded and memory will get reduced to 13.9 MB.

     

    //Looping through the media elemnt list (4 count) and making the Source =null. Will be stopping the

    media if playing too

    _mediaElementList[i].Source = null;


    2)When MediaElement Source is set .

     a) Page 1 is launched, say now the memory is 16MB.

     b) On "Navigate" button click Page 2 is launched.

    c)The LOH explicit GC will get triggered and memory will get reduced to 14 MB.

    d) MediaElement source is set in page 2:

    Looping through the media list and assigning a source.

    _mediaElementList.ElementAt(_index).SetSource(stream, file.ContentType);

    e) Now the page will be consisting of 4 media element's playing a video (source). The memory will rise to 58 MB.

    f)If I press back Page 2 all the 4 MediaElement Source will be set to null, Page 2 will be cleared from the stack and Page 1 will be loaded and memory is getting reduced to 18MB. 

     

    //Looping through the media elemnt list (4 count) and making the Source =null. Will be stopping the

    media if playing too

    _mediaElementList[i].Source = null;

    In this case even if I do Force GC the memory flow is from 14->58->LOH GC->18 MB. 3MB is getting held up. In Managed heap there is no reference to MediaElement or Page 2 when taken a snapshot on Page 1. Is this memory being held up by the MediaElement native memory pipe? If so any way to reclaim it ?c Any help will be much appreciated.

    Thanks ,

    Jose



    Friday, April 10, 2015 11:49 AM
  • Hi,

    Thanks for the response. I know the system will do a GC when it has got a memory Pressure( reach a threshold). But I was in the process of tracking and narrowing down a possible leak due to MediaElement setSource(). Even if i make it null when I navigate away from the page the entire allocated memory is not getting freed up leaving behind some residual memory. I doubt its something to do with the media pipe.

    So to dig in deep I wanted to make sure it has got nothing to do with the managed space page allocations for which an explicit GC was required to immediately collect (without waiting for the actual GC to kick in) all gen objects (using GC.Collect()). If the Page elements are getting collected on force GC when Source is null, means there is no retained reference of MediaElement/other referenced objects , and when I set the source and navigate away from the page some memory is retained, even if I do a Force GC with no reference in managed space. 

    Thx,

    Jose

    Friday, April 10, 2015 12:13 PM