Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
761 views
in Technique[技术] by (71.8m points)

c# - Remove Pages windows phone

I have a big project where my application keeps retaining a page which I navigated away from. The page is only used minimal, and have a lot of graphics, I therefore want it to be completely removed from memory.

I therefore used the following

 NavigationService.RemoveBackEntry();

Using the profiler I saw that, the above snippet made sure that I would only have 1 instance of the page. But as it is heavy with graphics I still want it to be completely removed from memory, i.e. no instances in the profiler.

In my big application I tried to unsubscribe to all events, introduce dispose/finalize and calling GC, it helped some but the instance still existed.

To exclude any stupid errors, I have made this small sample. Only Navigating between two dumb pages with a memory popup checker. But still 1-2 instances of the pages still exists. Is there anyway to force the removal of pages such that nothing of it is stored in memory?

I've added:

            while (App.RootFrame.RemoveBackEntry() != null) ;

To the OnNavigated to, and it removes all the pages except the first page I start on. I've used the debug analysis toolkit, and can see that no matter what the first page I start on does not get removed, when I navigate away from it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The WP Silverlight runtime will keep up to three pages in memory, even after being removed from the backstack. The reason for this behavior is still unclear to me, but I've found a (ugly) workaround: http://blogs.codes-sources.com/kookiz/archive/2013/11/11/wpdev-give-that-memory-back.aspx

Basically, override the OnNavigatedTo handler of your page, and force a garbage collection three times, separated by calls to the dispatcher:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    this.Dispatcher.BeginInvoke(() =>
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();

        this.Dispatcher.BeginInvoke(() =>
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();

            this.Dispatcher.BeginInvoke(() =>
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            });
        });
    });
}

As crazy as it sounds, it works.


In your case, you have another problem. You are keeping the page alive with your popup. Let me explain:

In the CreatePopups method, you create the popup and add it to the grid of the starting page. In the popup, you start a timer to call UpdateMemoryInfo at regular interval. The timer is kept alive by the .NET runtime until it's stopped. The timer keeps a reference on your popup because you're using an instance method as event handler. Your popup is keeping a reference to the grid through the Parent property. The grid is keeping a reference to the page through its own Parent property. So you just made your page immortal, for as long as your timer is ticking. To prove that the issue is there, just make the UpdateMemoryInfo method static (and remove all the UI updating code there's inside). Since the event handler is now static, the timer won't hold a reference to instance of popup. Run the profiler, and you'll see that the instance of the page is now reclaimed by the garbage collector as you expect.


Of course, it supposes that your pages have been removed from the back stack. Either by pressing the back key or calling the NavigationService.GoBack() method, or by manually removing them using NavigationService.RemoveBackEntry() (in case you only use forward navigation)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...