Bug 29554 - Crash when allocating large amounts of memory in cycle
Summary: Crash when allocating large amounts of memory in cycle
Alias: None
Product: Runtime
Classification: Mono
Component: GC ()
Version: 3.12.0
Hardware: PC Mac OS
: --- normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2015-04-29 15:50 UTC by Evgeny
Modified: 2016-11-08 21:08 UTC (History)
4 users (show)

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

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 GitHub or Developer Community 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 Evgeny 2015-04-29 15:50:19 UTC
A little bit of background. We've been experiencing crashes in our mobile app on some Android devices. The crash happens at some point after downloading a few large (28MB, 17MB, 25MB, etc.) JSON responses. While investigating the crash, I have created a piece of code with a very similar problem. Essentially, I don't understand why the memory is not getting garbage collected even though it is not referenced anymore.

The piece of code is below. It crashed on my Moto G device at iteration #21.

char[] list;
string content;

list = new char[30000000];
content = new string(list);

list = new char[30000000];
content = new string(list);

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);

for (int i = 0; i < 100; i++)
    Logger.Debug("Iteration #{0}", i);
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);

    list = new char[40000000];
    content = new string(list);

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);

    List<Contact> contacts = new List<Contact>();
    for (int j = 0; j < 150000; j++)
        contacts.Add(new Contact());

I realize this might be by design. But I'd like to better understand why this crashes only after completing 20 iterations of the cycle. And what are the possible workarounds.

I have tried testing the same piece of code with various GC settings such as no-lazy-sweep and stack-mark=precise. But nothing seems to resolve the problem.
Comment 1 Vlad Brezae 2016-09-23 20:53:09 UTC

Are you still able to get this crash using latest release ? What is the GC logging output of the application prior to the crash ? I think the logging is enabled by default, if not pass to the environment MONO_LOG_LEVEL=info MONO_LOG_MASK=gc
Comment 2 Nate Cook 2016-09-25 20:41:33 UTC
Vlad, Evgeny provided a code snippet in order to reproduce the problem. Your comment doesn't indicate whether or not you tried running the code snippet yourself, and if so, what the results were. Did you try the code snippet?
Comment 3 Vlad Brezae 2016-11-08 21:08:02 UTC
I was able to see some weird memory usage for a similar code snippet. The problem is that we are expecting memory to be reclaimed immediately by the GC since we are no longer using the allocated large objects. The problem is that references to these objects happen to remain on the stack since the example is so simple and the stack is not reused as it would be expected in a normal scenario. This is normally not a problem since the number of objects that can remain alive from references dangling on the stack is fairly small. Given it might take longer to reclaim objects due to these references, objects (especially large ones) should not be allocated in quick succession expecting that they will be reclaimed immediately.

I was able to reduce memory usage by 5 times on my test case by just calling a recursive method at each iteration which dirties the stack from any references. This is not really a bug, but we will consider doing optimisations that reduce the number of hanging references on the stack.