Bug 5858 - QLPreviewController huge memory allocation without disposing
Summary: QLPreviewController huge memory allocation without disposing
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: 5.3.x
Hardware: Other Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2012-06-25 18:14 UTC by Alex Anikin
Modified: 2012-07-03 20:48 UTC (History)
2 users (show)

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

screenshoots (2.75 MB, application/zip)
2012-06-25 18:15 UTC, Alex Anikin

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 Alex Anikin 2012-06-25 18:14:49 UTC
Hi -

We are using QLPreviewController in our project. (iOS app)
if (previewController != null) {
					previewController.DataSource.Dispose ();
					previewController.DataSource = null;
					previewController.ReloadData ();
					previewController.DismissViewController (false, null);
					previewController.Dispose ();
					previewController = null;

					GC.Collect (GC.MaxGeneration,GCCollectionMode.Forced);
				previewController = new QLPreviewController ();
				previewController.DataSource = new QLPreview ();
				previewController.View.Frame = view.Frame;
				previewController.View.Center = view.Center;
				previewController.View.Frame = new RectangleF (
				0, 0, previewController.View.Frame.Width, previewController.View.Frame.Height
				previewController.ReloadData ();
				view.AddSubview (previewController.View);

0. Initial state image (5.png), and do some actions -> memory allocation ~90Mb. 
1. Open file txt size=5Mb ->  memory allocation ~165 Mb. (6.png)
2. Using code above -> open tiny docx ->  memory allocation ~120 Mb. (where 30MB? not disposed?) (7.png)
3. Open pdf (280 pages) ->  memory allocation ~122Mb (8.png) (this much better, but huge pdfs can crash it too, but that 30Mb not disposed still)

If I open a lot of files - app crashes and memory allocations ~250Mb.

Profiler: (images 1-4.png) - in simulator i can't see the same allocation and large QLPreviewController instances. 

What I'm doing wrong? How should I dispose it? I tried many cases (recreation, one instance and so), but nothing still.

Contact me if you need more info. 

Comment 1 Alex Anikin 2012-06-25 18:15:46 UTC
Created attachment 2115 [details]
Comment 2 Rolf Bjarne Kvinge [MSFT] 2012-06-25 18:20:28 UTC
Can you provide a complete sample that shows the memory usage your seeing? This will also ensure we're using the exact same code your seeing the problems with.
Comment 3 Alex Anikin 2012-07-01 17:19:46 UTC
I created an example (updated Xamarin sample ): https://www.dropbox.com/sh/f02vbl5nyzbrf8t/8Q8VrL1sSb/QLPreviewerSample.zip

I tried many cases where and how to create controller. I was thinking about GC and memory disposing.
In dozens of experiments I can see just one case when the memory size was decreased after disposing of QLPreviewController.

One interesting thing I found. I did 2 buttons to simulate additional memory allocation and disposing (~20Mb). 
1. I was thinking - if I try to allocate more memory GC decide to dispose unusable memory for me -> dispose QLPreviewer. Nope.
2.  I was waiting, switching to other processes - very unpredictable. Sometimes I get more free memory, sometimes not.
3. And finally, when I working with huge list and do standard operations to add and clear memory not disposing. This is not related to GC.Collect. My solution to make force clearance - use GC.AddMemoryPressure(size_of_list) and GC.RemoveMemoryPressure(size_of_list). After that I can see - all allocated memory for list is disposed.
As i think - working with unmanaged resources and may be something same with QLPreviewer (I tried, you can see commented lines).
Comment 4 Alex Anikin 2012-07-02 03:33:00 UTC
Small addition.
If I allocate huge list - i can see in Mono Profiler. And can't see any memory increase for QLPreviewController, but XCode -> Instruments -> Activity Monitor shows another picture.
Comment 5 Rolf Bjarne Kvinge [MSFT] 2012-07-03 20:33:50 UTC
I have identified a leak in the 5.3.* beta releases which I'm now fixing.

A workaround for now is to add --noregistrar to the additional mtouch arguments in the project's iPhone Build options - can you try this to see if it makes any difference for you?
Comment 6 Rolf Bjarne Kvinge [MSFT] 2012-07-03 20:48:20 UTC

master: 130b27e41e83dde681fd29b74155795bfa00ae09

The fix will probably not be included in 5.3.5, it will only get into 5.3.6.

A few comments:
1. Mono(Touch) does not take memory pressure into account, so calling GC.Add|RemoveMemoryPressure doesn't change anything at all.
2. To get predictable garbage collection, the best is to just run it in a loop on a secondary thread:

new System.Threading.Thread (() =>
	while (true) {
		System.Threading.Thread.Sleep (1000);
		System.GC.Collect (System.GC.MaxGeneration);
}) { IsBackground = true }.Start ();

3. The reason the Mono Profiler doesn't see the memory QLPreviewController allocates, is because the Mono Profiler only sees managed memory. You have to use Instruments to see native memory usage too.