1) Writing some code.
![](http://3.bp.blogspot.com/-3zE0gVE7puI/Ta2uGIZTCQI/AAAAAAAAAeo/oD1uB9KxAsA/s400/A.png)
2) Launching from MonoDevelop:
![](http://3.bp.blogspot.com/-ls8pU-wnTN8/Ta2uQNTb-CI/AAAAAAAAAew/1T5qZ5h46A4/s400/B.png)
3) Debugging!
![](http://2.bp.blogspot.com/-hJ3LuAzLoyI/Ta2uZNka-1I/AAAAAAAAAe4/lMP9W-P8myk/s400/C.png)
4) Profit?
This should hopefully be available with the next MonoDevelop release :)
A cross platform open source .NET Framework based BitTorrent Client written in C#
void mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback);
struct _MonoProfiler {
const char *type_name;
GPtrArray *gchandles;
GPtrArray *stacktraces;
Moonlight::Mutex locker; /* used to ensure only one thread accesses the arrays */
static void track_gchandle (_MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj);
};
typedef _MonoProfiler MonoProfiler;
_MonoProfiler::_MonoProfiler ()
{
type_name = g_getenv ("GCHANDLES_FOR_TYPE");
gchandles = g_ptr_array_new ();
stacktraces = g_ptr_array_new_with_free_func (g_free);
/* Register the profiler with mono */
mono_profiler_install (this, NULL);
/* Supply a function for the gc_roots hook */
mono_profiler_install_gc_roots (track_gchandle, NULL);
/* Enable gc_roots tracking in the profiler so our hook is invoked */
mono_profiler_set_events (MONO_PROFILE_GC_ROOTS);
}
void
MonoProfiler::track_gchandle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj)
{
// Ignore anything that isn't a strong GC handle (docs say type == 2 is a strong gchandle)
if (type != 2)
return;
prof->locker.Lock ();
GPtrArray *gchandles = prof->gchandles;
GPtrArray *stacktraces = prof->stacktraces;
if (op == MONO_PROFILER_GC_HANDLE_CREATED) {
// Add the GCHandle to this array
g_ptr_array_add (gchandles, (gpointer) handle);
// If the target of the gchandle is of the correct type, store its stack trace
// Otherwise store NULL so that we can keep the index of the gchandle and corresponding
// stack trace in sync.
if (prof->type_name && !strcmp (prof->type_name, mono_class_get_name (mono_object_get_class(obj))))
g_ptr_array_add (stacktraces, get_stack_trace ());
else
g_ptr_array_add (stacktraces, NULL);
} else if (op == MONO_PROFILER_GC_HANDLE_DESTROYED) {
// Walk our list of gchandles and when we find the index of the destroyed handle
// remove the handle and corresponding stacktrace
for (int i = 0; i < (int)gchandles->len; i++) {
if (g_ptr_array_index (gchandles, i) == (gpointer) handle) {
g_ptr_array_remove_index_fast (gchandles, i);
g_ptr_array_remove_index_fast (stacktraces, i);
break;
}
}
}
prof->locker.Unlock ();
}
void
accumulate_g_ptr_array_by_type (gpointer data, gpointer user_data)
{
// The hashtable I passed in as the user_data in g_ptr_array_foreach
// which i am using to link a type name to a count
GHashTable *by_type = (GHashTable*) user_data;
// Get the MonoObject from the gchandle.
MonoObject *ob = mono_gchandle_get_target (GPOINTER_TO_INT (data));
// Get the type name from the mono_object
const char *name = mono_class_get_name (mono_object_get_class(ob));
// Find out how many instances we have already
int count = GPOINTER_TO_INT (g_hash_table_lookup (by_type, name)) + 1;
// Update the hashtable with an incremented count.
g_hash_table_insert (by_type, name, GINT_TO_POINTER (count));
}
1 instances GCHandled of type Surface
1 instances GCHandled of type Deployment
4 instances GCHandled of type NameScope
20 instances GCHandled of type ControlTemplate
218 instances GCHandled of type MonoType
3985 instances GCHandled of type Uri