У нас простой вопрос, но причина сложна. Мы являемся опытными разработчиками и провели много исследований о том, что может быть причиной этого. Мы надеемся, что разработчики MonoTouch могут работать с нами, чтобы определить, что является общей проблемой, с которой сталкиваются люди, и для которой пока не существует решения. Мы работали над этим более двух недель и не смогли его решить.
Вопрос в том, почему наше приложение MonoTouch ломается в сборщике мусора? Это не из памяти.
Ситуация такова, что у нас есть приложение, которое регулярно проверяет веб-сервис (возможно, каждые 5 секунд). Через некоторое время происходит сбой при прерывании управления памятью. Обычно это происходит примерно через полтора часа, но может длиться от десяти минут до ночи. Это происходит на всех наших тестовых устройствах (у нас их в общей сложности 7, охватывающих iOS3 и iOS4, iPod Touch, iPhone и iPad (1 и 2). После просмотра StackOverflow мы добавили System.Gc.Collect в таймере, прежде чем принимать какие-либо действие. Это немного улучшило ситуацию (требуется больше времени, чтобы потерпеть неудачу), но оно не исчезло. Стоит также добавить, что журнал памяти iPad показывает, что в нашем приложении 777 свободных блоков и 2041 используется, всего 26488 проводных страниц. Так как мы собрали мусор и не делаем ничего, отличного от того, что мы делали 5 секунд назад, кажется странным нехватка памяти.
Мы обновились до MonoTouch 4.0.1, но это не исправило.
вопросы StackOverflow, которые могут быть по той же проблеме, но не отвечать на нее: 5666905 / 4545383 / 5492469 / 5426733
Стек при сбое на iPad2 ниже. Ошибка может произойти в основном потоке или в http-потоке, но всегда происходит в этой последовательности GC_. Я включил код для менеджера памяти GC_remap ниже, с обсуждением.
Thread 10 Crashed:
0 libsystem_kernel.dylib 0x34b4da1c __pthread_kill + 8
1 libsystem_c.dylib 0x3646a3b4 pthread_kill + 52
2 libsystem_c.dylib 0x36462bf8 abort + 72
3 MyApp 0x004ca92c mono_handle_native_sigsegv (mini-exceptions.c:2249)
4 MyApp 0x004f2208 sigabrt_signal_handler (mini-posix.c:195)
5 libsystem_c.dylib 0x36475728 _sigtramp + 36
6 libsystem_c.dylib 0x3646a3b4 pthread_kill + 52
7 libsystem_c.dylib 0x36462bf8 abort + 72
8 MyApp 0x0061dc94 GC_remap (os_dep.c:2092)
9 MyApp 0x00611678 GC_allochblk_nth (allchblk.c:730)
10 MyApp 0x00611028 GC_allochblk (allchblk.c:561)
11 MyApp 0x0061d0e0 GC_new_hblk (new_hblk.c:253)
12 MyApp 0x006133d0 GC_allocobj (alloc.c:1116)
13 MyApp 0x00617d30 GC_generic_malloc_inner (malloc.c:136)
14 MyApp 0x00617f40 GC_generic_malloc (malloc.c:192)
15 MyApp 0x00618264 GC_malloc_atomic (malloc.c:262)
16 MyApp 0x005a46d4 mono_object_allocate_ptrfree (object.c:4221)
17 MyApp 0x005a4aa0 mono_string_new_size (object.c:4848)
18 MyApp 0x005c1b14 ves_icall_System_String_InternalAllocateStr (string-icalls.c:213)
19 MyApp 0x002d34c4 wrapper_managed_to_native_string_InternalAllocateStr_int + 52
20 MyApp 0x002cff5c string_ToLower_System_Globalization_CultureInfo + 56
21 MyApp 0x003e6ac0 System_Net_WebRequest_GetCreator_string + 40
22 MyApp 0x003e694c System_Net_WebRequest_Create_System_Uri + 48
23 MyApp 0x003e68d8 System_Net_WebRequest_Create_string + 64
24 MyApp 0x004489c4 MyApp_Services_Client_GetResponseContent_string + 152
25 MyApp 0x00446288 MyApp_Services_Client_GetCurrentQuestion_long_long + 916
26 MyApp 0x00196fcc MyApp_Iphone_RootViewController_RetrieveCurrentQuestion + 868
27 MyApp 0x002e6368 System_Threading_Thread_StartUnsafe + 168
28 MyApp 0x00306890 wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 192
29 MyApp 0x004b0274 mono_jit_runtime_invoke (mini.c:5746)
30 MyApp 0x0059f924 mono_runtime_invoke (object.c:2756)
31 MyApp 0x005a1350 mono_runtime_delegate_invoke (object.c:3421)
32 MyApp 0x005ca884 start_wrapper_internal (threads.c:788)
33 MyApp 0x005ca924 start_wrapper (threads.c:830)
34 MyApp 0x005ef4b8 thread_start_routine (wthreads.c:285)
35 MyApp 0x0061f1d0 GC_start_routine (pthread_support.c:1468)
36 libsystem_c.dylib 0x3646a30a _pthread_start + 242
37 libsystem_c.dylib 0x3646bbb4 thread_start + 0
Это код GC_remap, который, по-видимому, является точкой отказа, начиная с https://github.com/mono/mono/blob/master/libgc/os_dep.c
#ifdef NACL
{
/* NaCl doesn't expose mprotect, but mmap should work fine */
void * mmap_result;
mmap_result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
zero_fd, 0/* offset */);
if (mmap_result != (void *)start_addr) ABORT("mmap as mprotect failed");
/* Fake the return value as if mprotect succeeded. */
result = 0;
}
#else /* NACL */
result = mprotect(start_addr, len,
PROT_READ | PROT_WRITE | OPT_PROT_EXEC);
#endif /* NACL */
if (result != 0) {
GC_err_printf3(
"Mprotect failed at 0x%lx (length %ld) with errno %ld\n",
start_addr, len, errno);
ABORT("Mprotect remapping failed");
}
GC_unmapped_bytes -= len;
Может показаться, что ABORT вызван ошибкой функции mprotect. Нам не удалось получить код ошибки, поскольку проблема не проявляется на симуляторе. Функция mprotect, по-видимому, просто помечает память как доступную для чтения / записи / выполнения. Как диспетчер памяти передает параметры, которые вызывают его сбой? Это может быть неверный указатель или неправильная длина? Или определенные области или границы обрабатываются по-разному на iOS?
Код в https://github.com/mono/mono/blob/master/libgc/allchblk.c для GC_allochblk_nth подразумевает, что функция GC_remap вызывается только в том случае, если найденный блок памяти был действительным. (Этот файл не совсем соответствует номерам строк трассировки стека, поэтому, предположительно, это не совсем тот же файл.)
http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html говорит, что может произойти сбой с EACCES, EINVAL, ENOTSUP, которые равны 13, 22 и 45 соответственно. В одном из отчетов о SO говорится, что они получают ошибку 12 (ENOMEM). Я не уверен, что это значит, поскольку mprotect не должен выделять память, а в документации не говорится, что это правильно.
Более общая документация в http://linux.die.net/man/2/mprotect указывает, что ENOMEM может быть вызван "Внутренние структуры ядра не могут быть выделены. Или: адреса в диапазоне [addr, addr + len] недопустимы для адресного пространства или укажите одну или несколько страниц, которые не отображаются. " Как это могло быть?
Мы были бы очень благодарны за любые предложения о том, как мы можем продвинуться вперед. Мы не делаем ничего, кроме кода C #, и не делаем ничего, кроме периодического чтения https. Что мы можем сделать для улучшения отладки (мы ничего не можем отследить, так как приложение убито iOS). Мы попытались создать более простую демонстрацию, но она не дает сбоя достаточно быстро, чтобы ее стоило использовать. Если разработчик Novell MonoTouch хочет получить наш источник, мы можем предоставить его при условии явной конфиденциальности.