I know inline code is preferable, but there's a bunch of code that's needed to show that the problem actually occurs (such as leak detection). The project can be downloaded here: http://www.filefactory.com/file/c40b856/n/TestPopupLeak.zip
Here's what's happening:
For some reason, a popup using TiltEffect causes the last instance to be in it (the last child, I guess) to leak. I have created a small POC app that shows this.
In this (the smallest repro I was able to create), you do the following:
---> Another button will appear (this button is on a popup)
----> The second button will go away.
Repeat steps 1 and 2 a few times.
Tap the page title a few times (this causes a GC.Collect()).
Look at the output window – you will see that one instance of Grid and one instance of MyUserControl are leaking.
It looks to me like the last instance is kept in memory.
If you remove the tilt effect from the popup (comment out the lines that call TiltEffect), you will see the instances getting freed (the output window will tell you no refs are still in memory).
I have no idea why this is happening... Tried debugging into TiltEffect and it looks like all events get unhooked.
Here's the code that brings up the popup and hides it (the rest of the code handles the memory leaks and the dumb user control):
public partial class MainPage : PhoneApplicationPage
{
Popup popup;
Grid grid;
// Constructor
public MainPage()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
// This creates a Popup with a MyUserControl in it (wrapped in a grid).
// MyUserControl just contains a single button that when pressed calls the .action
// member.
popup = new Popup();
InstanceTracker.DebugAddObject(popup);
grid = new Grid() { Width = 400, Height = 400 };
// This tracks memory leaks and will output every 10 seconds what objects are
// still alive.
InstanceTracker.DebugAddObject(grid);
MyUserControl control = new MyUserControl();
control.action = () => button_Click(null, null);
InstanceTracker.DebugAddObject(control);
grid.Children.Add(control);
// Comment out this line and the one below that has a similar comment
// to make the bug go away.
Microsoft.Phone.Controls.TiltEffect.SetIsTiltEnabled(grid, true);
// That's it, show the popup.
popup.Child = grid;
popup.IsOpen = true;
}
void button_Click(object sender, RoutedEventArgs e)
{
// Disable the tilt and close the popup. Get rid of roots.
// Comment this out to make the problem go away.
Microsoft.Phone.Controls.TiltEffect.SetIsTiltEnabled(popup, false);
popup.IsOpen = false;
popup = null;
grid = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
private void PageTitle_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
// Collects all memory.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
Okay, the issue is with the Storyboard in the tilt effect holds a reference to the last animated object