Bug 40691 - Unmanaged memory leak when using DynamicMethod
Summary: Unmanaged memory leak when using DynamicMethod
Status: NEW
Alias: None
Product: Runtime
Classification: Mono
Component: Reflection ()
Version: 4.4.0 (C7)
Hardware: Other Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2016-04-25 22:14 UTC by David Straw
Modified: 2016-12-23 22:02 UTC (History)
6 users (show)

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

Simple repro program (1.69 KB, text/plain)
2016-04-25 22:14 UTC, David Straw

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 for Bug 40691 on GitHub or Developer Community if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: GitHub Markdown or Developer Community HTML
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:

Description David Straw 2016-04-25 22:14:27 UTC
Created attachment 15837 [details]
Simple repro program

Mono leaks unmanaged memory in apps using System.Reflection.Emit.DynamicMethod.CreateDelegate(). In the attached repro code, I found that the process VmRSS size (mapped to Process.WorkingSet64) increases continually at a rate of around 30-100 bytes per iteration, with slightly larger leak sizes occurring after around 1.5 million iterations.

I observed similar behavior between Mono 3.12, 4.2 and a recent build of 4.4. Sample output from Mono:

Iteration:  1,266,503   Working Set:  212,696 KiB   Private:  259,096 KiB   GC total:  4,165 KiB   bytes/iter:   35
Iteration:  1,358,982   Working Set:  216,644 KiB   Private:  260,500 KiB   GC total:  4,165 KiB   bytes/iter:   43
Iteration:  1,453,026   Working Set:  226,516 KiB   Private:  267,516 KiB   GC total:  4,165 KiB   bytes/iter:  107
Iteration:  1,545,923   Working Set:  235,120 KiB   Private:  272,884 KiB   GC total:  4,165 KiB   bytes/iter:   94
Iteration:  1,639,743   Working Set:  244,440 KiB   Private:  279,520 KiB   GC total:  4,165 KiB   bytes/iter:  101
Iteration:  1,738,010   Working Set:  255,576 KiB   Private:  287,796 KiB   GC total:  4,165 KiB   bytes/iter:  116
Iteration:  1,835,649   Working Set:  264,480 KiB   Private:  293,652 KiB   GC total:  4,165 KiB   bytes/iter:   93
Iteration:  1,934,673   Working Set:  274,440 KiB   Private:  300,472 KiB   GC total:  4,165 KiB   bytes/iter:  102
Iteration:  2,038,336   Working Set:  286,304 KiB   Private:  309,304 KiB   GC total:  4,165 KiB   bytes/iter:  117
Iteration:  2,141,641   Working Set:  296,812 KiB   Private:  315,668 KiB   GC total:  4,165 KiB   bytes/iter:  104
Iteration:  2,246,925   Working Set:  306,708 KiB   Private:  388,760 KiB   GC total:  4,165 KiB   bytes/iter:   96

Sample output on .NET on Windows (no leak):

Iteration: 10,690,225   Working Set:   33,072 KiB   Private:   31,028 KiB   GC total:  3,982 KiB   bytes/iter:    0
Iteration: 12,197,123   Working Set:   33,032 KiB   Private:   31,072 KiB   GC total:  4,963 KiB   bytes/iter:    0
Iteration: 13,765,662   Working Set:   34,148 KiB   Private:   32,056 KiB   GC total:  5,086 KiB   bytes/iter:    0
Iteration: 15,274,570   Working Set:   31,428 KiB   Private:   29,308 KiB   GC total:  2,162 KiB   bytes/iter:   -1
Iteration: 16,878,949   Working Set:   31,776 KiB   Private:   29,908 KiB   GC total:  2,834 KiB   bytes/iter:    0
Iteration: 18,365,320   Working Set:   33,712 KiB   Private:   32,676 KiB   GC total:  4,983 KiB   bytes/iter:    1
Iteration: 19,914,411   Working Set:   32,420 KiB   Private:   30,392 KiB   GC total:  3,352 KiB   bytes/iter:    0
Iteration: 21,469,287   Working Set:   33,980 KiB   Private:   31,884 KiB   GC total:  5,038 KiB   bytes/iter:    1

This appears likely to be the cause of our application leaking hundreds of MiB and even into the GiB range during testing over hours/days. Our managed memory is not growing, and we see many calls to DynamicMethod:create_dynamic_method when using mono --trace (we're also looking at which of our dependencies seems to be making such heavy use of dynamic methods, but hopefully we won't need to work around that).
Comment 1 David Straw 2016-05-04 17:16:20 UTC
FYI we found that NHibernate is a big user of dynamic methods, at times creating multiple dynamic methods for the execution of a single query. Therefore it seems that with this memory leak, it's likely that any application using NHibernate extensively will run into memory problems after running for a while on Mono.
Comment 2 Zoltan Varga 2016-05-15 07:06:19 UTC
I can reproduce this with mono 4.4, but not with master.
Comment 3 Brandon White 2016-12-23 22:02:30 UTC
This may be same or similar to https://bugzilla.xamarin.com/show_bug.cgi?id=39181