Bug 60986 - Memory leak when marshalling Delegate to native code
Summary: Memory leak when marshalling Delegate to native code
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: Interop (show other bugs)
Version: 5.8 (2017-10)
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Vlad Brezae
URL:
Depends on:
Blocks:
 
Reported: 2017-12-05 13:15 UTC by d.obrazcov
Modified: 2018-02-11 16:30 UTC (History)
6 users (show)

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


Attachments
Test project that reproduce memory leak (5.24 KB, application/x-zip-compressed)
2017-12-05 13:16 UTC, d.obrazcov
Details
Profile log (1.15 MB, application/x-zip-compressed)
2017-12-05 13:18 UTC, d.obrazcov
Details


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:
Status:
RESOLVED FIXED

Description d.obrazcov 2017-12-05 13:15:19 UTC
In our project we send callback delegate to native code and found a memory leak at runtime.

This is a sample project that reproduce the problem.

class CallbackOwner
{
   [UnmanagedFunctionPointer( CallingConvention.Cdecl )]
   internal delegate void NativeFunctionCallback(int arg);

   [DllImport("libnative", CallingConvention = CallingConvention.Cdecl)]
   internal static extern void native_function(int arg, NativeFunctionCallback cb);

   private NativeFunctionCallback _cb;

   public CallbackOwner()
   {
      _cb = CallbackImplementation;
   }

   public void Run(int n)
   {
      native_function( n, _cb ); // Expecting leak here!
   }

   private void CallbackImplementation( int arg )
   {
      Console.WriteLine( arg );
   }
}

And write some loop to test

int n = 0;
while ( true )
{
   new CallbackOwner().Run( ++n );

   // Collect managed memory.
   if (n%1000 == 0)
      GC.Collect();
}

"libnative" is a simple test programm that only execute callback.

Full test project added to attachement.

This leak reproduced on Mac and Linux on Windows all fine. With mono-boehm leak not reproduced, only with SGen.

Profiler show memory leak at:

Leak: 0x7f81e74001c0  size=16  zone: DefaultMallocZone_0x1068f1000
	0x03b0600e 0x00000000 0x00000000 0x00000000 	.`..............
	Call stack: [thread 0x7fffb321e340]: | start | main | mono_main | mono_jit_exec | do_exec_main_checked | do_runtime_invoke | mono_jit_runtime_invoke | 0x106a0d427 | mono_delegate_to_ftnptr | mono_jit_compile_method_with_opt | mono_jit_compile_method_inner | mini_method_compile | mono_save_seq_point_info | mono_seq_point_info_new | monoeg_malloc0 | calloc | malloc_zone_calloc
Comment 1 d.obrazcov 2017-12-05 13:16:41 UTC
Created attachment 25912 [details]
Test project that reproduce memory leak
Comment 2 d.obrazcov 2017-12-05 13:18:25 UTC
Created attachment 25913 [details]
Profile log
Comment 3 a.petrov 2017-12-05 13:28:12 UTC
"$ leaks mono-sgen" revealed a lot of leaks like this one:

----------
Leak: 0x7f81e74001c0  size=16  zone: DefaultMallocZone_0x1068f1000
    0x03b0600e 0x00000000 0x00000000 0x00000000     .`..............
    Call stack: [thread 0x7fffb321e340]: | start | main | mono_main | mono_jit_exec | do_exec_main_checked | do_runtime_invoke | mono_jit_runtime_invoke | 0x106a0d427 | mono_delegate_to_ftnptr | mono_jit_compile_method_with_opt | mono_jit_compile_method_inner | mini_method_compile | mono_save_seq_point_info | mono_seq_point_info_new | monoeg_malloc0 | calloc | malloc_zone_calloc 
----------

We suspect that `mono_destroy_compile()` is not freeing MonoCompile's `seq_point_info` field. Looks like its missing `mono_seq_point_info_free()` call.
Comment 4 a.petrov 2017-12-05 23:03:53 UTC
Looks like previously reported leaks of 5.4 were fixed by https://github.com/mono/mono/commit/4cf2b5feee0c3aed6b747105c141f48165bd0ae1#diff-889eecc0e02f623fc21d69e97f0983c4

But memory of the sample application attached here still is growing rapidly. Looks like  stub functions generated for delegates marshaling are never deleted from memory (mono/metadata/marshal.c: mono_delegate_to_ftnptr()).
Comment 5 Ludovic Henry 2018-01-16 20:07:38 UTC
https://github.com/mono/mono/pull/6505