#include #include #include #include #include #include #include #include #define FIELD_ATTRIBUTE_STATIC 0x10 #define FIELD_ATTRIBUTE_HAS_FIELD_RVA 0x100 static int memory_usage (MonoObject *obj, GHashTable *visited); static int memory_usage_array (MonoArray *array, GHashTable *visited) { int total = 0; MonoClass *array_class = mono_object_get_class ((MonoObject *) array); MonoClass *element_class = mono_class_get_element_class (array_class); MonoType *element_type = mono_class_get_type (element_class); if (MONO_TYPE_IS_REFERENCE (element_type)) { int i; for (i = 0; i < mono_array_length (array); i++) { MonoObject *element = mono_array_get (array, gpointer, i); if (element != NULL) total += memory_usage (element, visited); } } return total; } static int memory_usage (MonoObject *obj, GHashTable *visited) { int total = 0; MonoClass *klass; MonoType *type; gpointer iter = NULL; MonoClassField *field; if (g_hash_table_lookup (visited, obj)) return 0; g_hash_table_insert (visited, obj, obj); klass = mono_object_get_class (obj); type = mono_class_get_type (klass); /* This is an array, so drill down into it */ if (type->type == MONO_TYPE_SZARRAY) total += memory_usage_array ((MonoArray *) obj, visited); while ((field = mono_class_get_fields (klass, &iter)) != NULL) { MonoType *ftype = mono_field_get_type (field); gpointer value; if ((ftype->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)) != 0) continue; /* FIXME: There are probably other types we need to drill down into */ switch (ftype->type) { case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: mono_field_get_value (obj, field, &value); if (value != NULL) total += memory_usage ((MonoObject *) value, visited); break; case MONO_TYPE_STRING: mono_field_get_value (obj, field, &value); if (value != NULL) total += mono_object_get_size ((MonoObject *) value); break; case MONO_TYPE_SZARRAY: mono_field_get_value (obj, field, &value); if (value != NULL) { total += memory_usage_array ((MonoArray *) value, visited); total += mono_object_get_size ((MonoObject *) value); } break; default: /* printf ("Got type 0x%x\n", ftype->type); */ /* ignore, this will be included in mono_object_get_size () */ break; } } total += mono_object_get_size (obj); return total; } /* * Only returns data for instances, not for static fields, those might * be larger, or hold larger structures */ static int GetMemoryUsage (MonoObject *this) { GHashTable *visited = g_hash_table_new (NULL, NULL); int n; n = memory_usage (this, visited); g_hash_table_destroy (visited); return n; } static int installed = 0; void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo) { if (installed) return; mono_add_internal_call ("Mono.ObjectServices.ObjectInspector::GetMemoryUsage", GetMemoryUsage); installed = 1; } void mono_profiler_init_size (const char *desc) { MonoProfilerHandle handle = mono_profiler_create (NULL); mono_profiler_set_jit_done_callback (handle, install_icall); }