[Mono-bugs] [Bug 78628][Nor] New - mono leaks mach ports
bugzilla-daemon at bugzilla.ximian.com
bugzilla-daemon at bugzilla.ximian.com
Tue Jun 13 18:05:24 EDT 2006
Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.
Changed by allan at imeem.com.
http://bugzilla.ximian.com/show_bug.cgi?id=78628
--- shadow/78628 2006-06-13 18:05:24.000000000 -0400
+++ shadow/78628.tmp.20224 2006-06-13 18:05:24.000000000 -0400
@@ -0,0 +1,177 @@
+Bug#: 78628
+Product: Mono: Runtime
+Version: 1.1
+OS: unknown
+OS Details: OS X 10.4.6, PPC and x86
+Status: NEW
+Resolution:
+Severity: Unknown
+Priority: Normal
+Component: misc
+AssignedTo: dick at ximian.com
+ReportedBy: allan at imeem.com
+QAContact: mono-bugs at ximian.com
+TargetMilestone: ---
+URL:
+Summary: mono leaks mach ports
+
+Please fill in this template when reporting a bug, unless you know what you are doing.
+Description of Problem:
+
+Mono leaks mach ports. Sample code and examination of the darwin_stop_world.c suggests that
+the problem is at least partially threading/garbage collection related.
+
+Steps to reproduce the problem:
+1. Here is sample code the reproduces the problem. It is also available at http://blargle.com/
+~allan/leaky.tar.bz2 . Note that there are two samples: one managed and one un-managed.
+
+The managed example:
+
+using System;
+using System.Collections;
+using System.Text;
+using System.Threading;
+
+namespace blargle
+{
+ class Leaky
+ {
+ private static int thread_chunksize = 256;
+ static void Main(string[] args)
+ {
+ ArrayList threads = new ArrayList(thread_chunksize);
+ while(true)
+ {
+ for(int i = 0; i < thread_chunksize; i++)
+ {
+ Thread newThread = new Thread(new ThreadStart(Blargle));
+ newThread.Start();
+ threads.Add(newThread);
+ }
+
+ foreach(Thread thread in threads)
+ {
+ thread.Join();
+ }
+
+ Thread.Sleep(2000);
+ }
+ }
+
+ static void Blargle()
+ {
+ //just doing stuff to cause memory allocation.
+ StringBuilder stringBuilder = new StringBuilder();
+
+ for(int i = 0; i < 555; i++)
+ {
+ stringBuilder.Append("Blargle");
+ string falargle = stringBuilder.ToString();
+ }
+ }
+ }
+}
+
+The embedding example:
+
+#include <pthread.h>
+#include <mono/jit/jit.h>
+#include <mono/metadata/metadata.h>
+#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/threads.h>
+#include <mono/metadata/appdomain.h>
+
+#define CHUNK_THREADCOUNT 32
+
+static void *thread_function(void *monoDomain) {
+ printf("Attaching thread...\n");
+ MonoThread *monoThread = mono_thread_attach((MonoDomain *)monoDomain);
+ printf("Thread (%p) attached.\n", monoThread);
+
+ //normally, some threaded stuff would happen here.
+
+ printf("Detaching thread (%p)\n", monoThread);
+ mono_thread_detach(monoThread);
+ printf("Thread (%p) detached.\n", monoThread);
+}
+
+int main(int argc, char *argv[]) {
+
+ mono_set_defaults(0, mono_parse_default_optimizations(NULL));
+ MonoDomain *monoDomain = mono_jit_init("leaky");
+
+ while(TRUE) {
+ pthread_t threads[CHUNK_THREADCOUNT];
+ int i;
+
+ for(i = 0; i < CHUNK_THREADCOUNT; i++)
+ pthread_create(threads + i, NULL, thread_function, monoDomain);
+
+
+ for(i = 0; i < CHUNK_THREADCOUNT; i++) {
+ pthread_join(threads[i], NULL);
+ pthread_detach(threads[i]);
+ }
+
+ sleep(1);
+ }
+
+ return(0);
+}
+
+Actual Results:
+
+In both examples, port usage (as reported by Activity Monitor, under the "Statistics" tab of the
+process inspector) rises without bound.
+
+The managed example will sometimes die like this:
+
+cromulent:~/mono/leaky allan$ mono leaky.exe
+
+** (leaky.exe:25370): WARNING **: CreateThread: error creating thread handle
+
+** (leaky.exe:25370): WARNING **: ves_icall_System_Threading_Thread_Thread_internal:
+CreateThread error 0x1f
+
+Unhandled Exception: System.SystemException: Thread creation failed.
+ at System.Threading.Thread.Start () [0x00000]
+ at blargle.Leaky.Main (System.String[] args) [0x00000]
+
+** (leaky.exe:25370): WARNING **: _wapi_thread_apc_pending: error looking up thread handle
+0x108
+
+The embedding example will eventually bomb out like this:
+
+thread_terminate(mach_thread_self()) failed: (ipc/send) invalid destination port
+
+Expected Results:
+
+Port count should fluctuate, but not rise without bound. Programs should definitely not bomb
+out.
+
+How often does this happen?
+
+Always.
+
+Additional Information:
+I will attach a GC patch that seems to halve the number of ports leaked per thread chunk, at least
+for the embedding example. The patch is rough and has whitespace changes I made just so I
+could visually parse the code, as well as comment-out debugging GC_printfs.
+
+------- Additional Comments From allan at imeem.com 2006-06-12 18:33 -------
+Created an attachment (id=17166)
+rough patch for darwin_stop_world.c that reduces mach port leaks
+
+
+------- Additional Comments From allan at imeem.com 2006-06-12 18:34 -------
+*** Bug 78615 has been marked as a duplicate of this bug. ***
+
+------- Additional Comments From allan at imeem.com 2006-06-13 18:05 -------
+At Miguel's suggestion, I tried using an upstream version of libgc instead of the one included
+with Mono. Using libgc 6.6, it looks like the port leaks caused by thread registration (seen
+with the embedded sample code) have gone away, but the leaks that seem to be caused by
+garbage collection are still present. Also, 6.6 seems to have a pretty bad memory leak that
+does not exist in the Mono SVN version of libgc. I will attach a version of my previous GC
+patch that fixes the memory leak and also calls mach_port_deallocate() (libgc 6.6 was also
+missing those calls).
More information about the mono-bugs
mailing list