Bug 25883 - X.Forms -- StackLayout.Children.Clear & changing Frame.Container cause Memory Leak
Summary: X.Forms -- StackLayout.Children.Clear & changing Frame.Container cause Memory...
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 1.3.0
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2015-01-09 13:09 UTC by Howard
Modified: 2015-02-13 10:55 UTC (History)
4 users (show)

Is this bug a regression?: ---
Last known good build:

C# file with a simplified example (2.12 KB, text/plain)
2015-01-17 15:26 UTC, Howard

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Howard 2015-01-09 13:09:03 UTC
Original application was failing after running .ChildrenClear() followed by .Children.Add() about 20 times with the following in Application Output:

[dalvikvm-heap] Clamp target GC heap from 130.405MB to 128.000MB
[dalvikvm-heap] Clamp target GC heap from 133.096MB to 128.000MB
[dalvikvm-heap] Forcing collection of SoftReferences for 2785768-byte allocation
[dalvikvm-heap] Clamp target GC heap from 137.088MB to 128.000MB
[dalvikvm-heap] Out of memory on a 2785768-byte allocation.

After adding GC.Collect immediately following the Children.Add statements I noticed the following also being reported in the Application Output:

[Mono] GC_OLD_BRIDGE num-objects 62 num_hash_entries 63 sccs size 63 init 0.00ms df1 0.19ms sort 0.01ms dfs2 0.32ms setup-cb 0.07ms free-data 0.09ms links 1/1/1/1 dfs passes 126/64
[Mono] GC_MAJOR: (user request) pause 4.78ms, total 4.93ms, bridge 31.62ms major 1088K/1072K los 8K/8K

Both num-objects and num_hash_entries continue to climb as the screen is rotated until program crashes.

It appears that .Children.Clear() does not return all the memory used by the former contents.
I switched from using a StackLayout for the page container to a Frame. Same thing happened as the contents were changed.

The results are reproducible on my system however the problems only occur with certain contents (See Code Below).

Run in Forms 1.3 and watch Application Output. As you rotate the screen back and forth between portrait and landscape I am hoping you can reproduce the increasing num-objects and num_hash_entries.

using System;
using Xamarin.Forms;

namespace Crash
	class Crash : ContentPage

		StackLayout		layoutV;
		StackLayout		layoutH;
		Frame			frameP;
		StackLayout		stackP;
		bool			isPortrait;

		public Crash ()
			// It appears if Frame is used, GC reports increasing num-objects
 			//   and num_hash_entries as setOrientation switches back and forth
			//   between the layouts below.
			// If H_V or S_V are used in layoutV and LayoutH there is no problem
			// If F_V is used in layoutV and LayoutH the problem occurs
			Label L_V 		= new Label { Text = "V Text" };
			Label L_H 		= new Label { Text = "H Text" };
			Frame F_V 		= new Frame { Content=L_V };
			Frame F_H 		= new Frame { Content=L_H };
			StackLayout S_V	= new StackLayout { Children = { L_V }};
			StackLayout S_H	= new StackLayout { Children = { L_H }};

			layoutV	= new StackLayout { Children = { F_V }}; // if H_V or S_V no problem; if F_V increments
			layoutH	= new StackLayout { Children = { F_H }}; // if L_V or S_V no problem; if F_V increments
//			frameP	= new Frame { Content=layoutV };
			stackP	= new StackLayout { Children = { layoutV }};
			isPortrait	= true;

//			this.Content 	= frameP;
			this.Content	= stackP;
			this.SizeChanged += (sender, e) => setOrientation(this);

		void setOrientation (Page p)
			if ( !isPortrait && (p.Width < p.Height) ) {
				// When layoutP.Content is reassigned it does not release
				//   prior content to the GC depending on the type
				//   of content contained in layoutV amd layoutH
//				frameP.Content	= layoutV;

				// Likewise, .Children.Clear / Children.Add results in a memory leak
				//   depending on type of content contained in layoutV and layoutH
				isPortrait = true;
			if ( isPortrait && (p.Width > p.Height) ) {
//				frameP.Content	= layoutH;
				isPortrait = false;

If I am missing something obvious I’d be grateful for an explanation. Have spent a bunch of time trying to get the ability to handle screen rotations and no joy.

Comment 1 Howard 2015-01-09 15:34:01 UTC
FYI, I checked the heap growth with the above code using F_V & F_H (Frame) vs. S_V & S_H (Stack).

According to the Android Device Monitor the heap did grow in both cases.

(S_V/S_H) In the case of using the layout containing the StackLayout the allocated heap grew at a rate of about 10KB per screen change.

(F_V/H_V) In the case of using the layout containing the Frame it the allocated heap grew at a rate of about 1MB per screen change.

With the real page which looks like a calculator with 12 buttons 5 labels and a progress bar... the allocated heap grows at about 10MB per screen rotation.

Already gave up XAML due to the bug that requires a full clean and rebuild every time we made any change to the XAML page. Now I guess will be giving up on Forms and back to mono. This app would never get through Apples QC.
Comment 2 Howard 2015-01-17 15:26:27 UTC
Created attachment 9392 [details]
C# file with a simplified example
Comment 3 Jason Smith [MSFT] 2015-02-13 10:55:29 UTC
I have validated that the frame leak is resolved and the other leak appears to be gone as well. (though there is churn on the allocations that eventually do get freed)