Bug 1418 - Garbage Collector gets stuck at 100% on iPad 1
Summary: Garbage Collector gets stuck at 100% on iPad 1
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 4.x
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2011-10-11 09:11 UTC by René Ruppert
Modified: 2012-04-24 08:25 UTC (History)
4 users (show)

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

CPU_Load (78.82 KB, image/png)
2011-10-11 09:11 UTC, René Ruppert

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 René Ruppert 2011-10-11 09:11:18 UTC
Created attachment 671 [details]

I have written a PDF viewer that has a UISlider. Sliding it generates previews of the target page. The preview is rendered in a separate thread.
On iPad 1 creating and cancelling only one thread makes the device unusable. CPU is at 100%. From Instruments I can see that it is stuck in the Garbage Collector.
See screenshot.
Comment 1 René Ruppert 2011-10-11 09:15:17 UTC
I is of course possible that I am doing something I should not do, but I am not aware what that would be.
Here's the method that gets called whenever UISlider changes it value (note that chaing value means dragging it quite a bit), so it's not that I cerate and destroy millions of threads.
Any ideas why this drives GC nuts? 

private void RenderScrollPreviewImages (int iPage)
			if(this.oScrollSliderPreview == null)
				SizeF oSize = new SizeF(150, 200);
				RectangleF oFrame = new RectangleF(new PointF (this.View.Bounds.Width - oSize.Width - 50, this.GetScrollSliderOffset (oSize)), oSize);
				this.oScrollSliderPreview = new UIView(oFrame);
				this.oScrollSliderPreview.UserInteractionEnabled = false;
				this.oScrollSliderPreview.Layer.BorderWidth = 2.0f;
				this.oScrollSliderPreview.Layer.BorderColor = UIColor.Black.CGColor;
				this.oScrollSliderPreview.BackgroundColor = UIColor.White;
				UIActivityIndicatorView oIndicator = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray);
				oIndicator.Center = new PointF(this.oScrollSliderPreview.Bounds.Width/2, this.oScrollSliderPreview.Bounds.Height/2);
			if(this.oScrollSliderPreview.Subviews.Length > 0)
				foreach(UIView oSubview in this.oScrollSliderPreview.Subviews)
					if(!(oSubview is UIActivityIndicatorView))
			if(this.oRenderScrollPreviewImagesThread != null)
					// Expected.
			this.oRenderScrollPreviewImagesThread = new Thread (delegate()
				using (var oPool = new NSAutoreleasePool())
						UIImageView oImgView = PdfViewerHelpers.GetLowResPagePreview (this.oPdfDoc.GetPage (iPage), new RectangleF (0, 0, 150, 200));
							if(this.oScrollSliderPreview != null)
								oImgView.Center = new PointF(this.oScrollSliderPreview.Bounds.Width/2, this.oScrollSliderPreview.Bounds.Height/2);
					catch (Exception)
			this.oRenderScrollPreviewImagesThread.Start ();
Comment 2 René Ruppert 2011-10-11 09:35:54 UTC
Maybe not clear enough: the CPU remains at 100% forever. It will never catch up again until I kill the app.
I get this with DEBUG and RELEASE, with sGen and without.
The code responsible fro the issue in the end is the line:

UIImageView oImgView =
PdfViewerHelpers.GetLowResPagePreview (this.oPdfDoc.GetPage (iPage), new
RectangleF (0, 0, 150, 200));

It is creating an image view preview of a PDF page. Anything obviously fishy with that code?

internal static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect)
			RectangleF oPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media);
			// If preview is requested for the PDF index view, render a smaller version.
			float fAspectScale = 1.0f;
			if (!oTargetRect.IsEmpty)
				fAspectScale = GetAspectZoomFactor (oTargetRect.Size, oPdfPageRect.Size, false);
				// Resize the PDF page so that it fits the target rectangle.
				oPdfPageRect = new RectangleF (new PointF (0, 0), GetFittingBox (oTargetRect.Size, oPdfPageRect.Size));
			// Create a low res image representation of the PDF page to display before the TiledPDFView
			// renders its content.
			UIGraphics.BeginImageContext (oPdfPageRect.Size);
			CGContext oContext = UIGraphics.GetCurrentContext ();
			oContext.SaveState ();
			// First fill the background with white.
			oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f);
			oContext.FillRect (oPdfPageRect);
			// Flip the context so that the PDF page is rendered right side up.
			oContext.TranslateCTM (0.0f, oPdfPageRect.Size.Height);
			oContext.ScaleCTM (1.0f, -1.0f);
			// Scale the context so that the PDF page is rendered 
			// at the correct size for the zoom level.
			oContext.ScaleCTM (fAspectScale, fAspectScale);
			oContext.DrawPDFPage (oPdfPage);
			oContext.RestoreState ();
			UIImage oBackgroundImage = UIGraphics.GetImageFromCurrentImageContext ();
			UIGraphics.EndImageContext ();
			UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage);
			oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size);
			oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill;
			oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None;
			return oBackgroundImageView;
Comment 3 Rolf Bjarne Kvinge [MSFT] 2011-10-11 17:09:11 UTC
It's not the GC thread, it's your thread that's stuck (the fact that there's a GC_start_routine method at the top of the stack trace doesn't mean that it's the GC thread, just that it's a thread the GC knows about).

Second maybe you could find out which exception is getting thrown? That might help you figure out what's going on.
Comment 4 Miguel de Icaza [MSFT] 2011-10-20 20:32:04 UTC
The only fishy bit that I see in this code is the use of Thread.Abort which is a heavy-handed approach that can leave the system in an inconsistent state.

It is best if you use Thread.Interrupt as it is a lot milder and will properly unwind code and release resources.
Comment 5 René Ruppert 2012-04-24 08:25:53 UTC
I cannot reproduce anymore.