На моно есть boehm и sgen (может еще что-то есть, но я не знаю). Это два разных GC по идеологии. Мы пользуемся sgen (это generational GC), а то, что вы описали это boehm. Можно изучить вопрос, но даже если так, то в любом случае sgen себя показывает лучше чем boehm в наших условиях.
Да, как я написал, форматирование строк у нас всплыло в основном в создании различных исключений, а в этом случае боксинг не самая большая ваша проблема. Перед тем, как дойти до оптимизирования боксинга мы не один месяц правили другие участки кода.
Отвечаю сразу на два вопроса по тому, насколько это поможет в ваших проектах. Сложно сказать, я же не видел ваш код. Вообще, как я написал вначале, проблемы производительности обычно лежат на уровень выше и надо просто запускать профайлер и решать одну проблему за другой. Насчет того, как найти в профайлере. В профайлере можно часто увидеть различные value типы в списках объектов, живущих на куче. Если их очень много, и они выходят на первые строки, то надо начинать задумываться. Мы смотрели блокировки и получили такой stack trace (но это я уже забегаю в тему следующей статьи):
stack
#4 0x00007ffeda83cc72 in __lll_lock_wait () from /lib/libpthread.so.0
#5 0x00007ffeda838179 in _L_lock_953 () from /lib/libpthread.so.0
#6 0x00007ffeda837f9b in pthread_mutex_lock () from /lib/libpthread.so.0
#7 0x00000000005f9269 in mono_gc_alloc_obj (vtable=vtable(«System.Int32»), size=20) at sgen-alloc.c:468
#8 0x00000000005b4b4d in mono_object_new_alloc_specific (vtable=vtable(0x2)) at object.c:4481
#9 0x00000000005b55e8 in mono_object_new_specific (vtable=vtable(«System.Int32»)) at object.c:4472
#10 0x00000000005379a9 in ves_icall_System_Enum_get_value (this=0x7ffed94ac8f0) at icall.c:3093
#11 0x00000000415197dd in (wrapper managed-to-native) System.Enum:get_value (param0=<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
140732543977712) at :668
#12 0x0000000041643994 in System.Enum:HasFlag (this=<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
140732543977712, flag=<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
140732543977736) at /root/mike/mono/mcs/class/corlib/System/Enum.cs:1991
А под моно происходит вот что:
#define LOCK_GC do { mono_mutex_lock (&gc_mutex); MONO_GC_LOCKED (); } while (0)
LOCK_GC;
res = mono_gc_alloc_obj_nolock (vtable, size);
Но я почти уверен, что что-то подобное и в .NET происходит, потому что мы там тоже видим lock.
#5 0x00007ffeda838179 in _L_lock_953 () from /lib/libpthread.so.0
#6 0x00007ffeda837f9b in pthread_mutex_lock () from /lib/libpthread.so.0
#7 0x00000000005f9269 in mono_gc_alloc_obj (vtable=vtable(«System.Int32»), size=20) at sgen-alloc.c:468
#8 0x00000000005b4b4d in mono_object_new_alloc_specific (vtable=vtable(0x2)) at object.c:4481
#9 0x00000000005b55e8 in mono_object_new_specific (vtable=vtable(«System.Int32»)) at object.c:4472
#10 0x00000000005379a9 in ves_icall_System_Enum_get_value (this=0x7ffed94ac8f0) at icall.c:3093
#11 0x00000000415197dd in (wrapper managed-to-native) System.Enum:get_value (param0=<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
140732543977712) at :668
#12 0x0000000041643994 in System.Enum:HasFlag (this=<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
140732543977712, flag=<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
<type 'exceptions.RuntimeError'>
Cannot access memory at address 0x190000000002b2
140732543977736) at /root/mike/mono/mcs/class/corlib/System/Enum.cs:1991