ios memory-management xamarin.ios

ios - ¿Por qué nuestra aplicación MonoTouch se está rompiendo en el recolector de basura? No esta fuera de memoria



memory-management xamarin.ios (2)

Tenemos una pregunta simple, pero la causa es complicada. Somos desarrolladores experimentados y hemos investigado mucho sobre lo que puede estar causando esto. Esperamos que los desarrolladores de MonoTouch puedan trabajar con nosotros para identificar lo que parece ser un problema común que tienen las personas y para el que todavía no existe una solución. Hemos estado trabajando en esto durante más de dos semanas y no hemos podido resolverlo.

La pregunta es: ¿Por qué nuestra aplicación MonoTouch se está rompiendo en el recolector de basura? No está fuera de la memoria.

La situación es que tenemos una aplicación que verifica un servicio web con regularidad (tal vez cada 5 segundos). Después de un período de tiempo falla con un aborto de administración de memoria. Esto suele suceder después de aproximadamente una hora y media, pero puede ser desde diez minutos hasta la noche. Esto sucede en todos nuestros dispositivos de prueba (tenemos 7 en total que cubren iOS3 y iOS4, iPod Touch, iPhones y iPads (1 y 2). Después de buscar en StackOverflow, hemos agregado un System.Gc.Collect en un temporizador antes de tomar cualquier Esto mejoró un poco las cosas (tarda más en fallar), pero no desapareció. También vale la pena agregar que el registro de memoria del iPad muestra que hay 777 bloques libres y 2041 en uso por nuestra aplicación. con un total de 26488 páginas cableadas. Dado que hemos recolectado basura y no estamos haciendo nada diferente a lo que hicimos 5 segundos antes, parece extraño quedarse sin memoria.

Actualizamos a MonoTouch 4.0.1 pero eso no lo ha arreglado.

Preguntas de StackOverflow que pueden estar en el mismo problema, pero que no responden: 5426733

La pila al fallar en un iPad2 está abajo. El error puede ocurrir en el hilo principal o en un hilo http, pero siempre va en esta secuencia GC_. He incluido el código para el administrador de memoria GC_remap a continuación, con discusión.

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

Este es el código GC_remap que parece ser el punto de falla, desde 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;

Parece que ABORT es causado por la falla de la función mprotect. No hemos podido obtener el código de falla porque el problema no se manifiesta en el simulador. La función mprotect aparece solo para marcar la memoria como accesible para lectura / escritura / ejecución. ¿Cómo está pasando el administrador de memoria los parámetros que hacen que falle? ¿Podría estar pasando un puntero incorrecto o una longitud incorrecta? ¿O son ciertas áreas o límites manejados de manera diferente en iOS?

El código en https://github.com/mono/mono/blob/master/libgc/allchblk.c para GC_allochblk_nth implica que la función GC_remap solo se llama si el bloque de memoria encontrado fue válido. (Este archivo no coincide exactamente con los números de línea del seguimiento de la pila, por lo que probablemente no es exactamente el mismo archivo).

http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html dice que podría fallar con EACCES, EINVAL, ENOTSUP, que son 13, 22 y 45 respectivamente . Uno de los informes de SO dice que obtuvieron un error 12 (ENOMEM). No estoy seguro de lo que eso significa, ya que mprotect no debería estar asignando memoria, y la documentación no dice que sea válida.

Una documentación más genérica en http://linux.die.net/man/2/mprotect indica que ENOMEM puede ser causada por "No se pudieron asignar las estructuras internas del kernel. O: las direcciones en el rango [addr, addr + len] son no válido para el espacio de direcciones del proceso, o especifique una o más páginas que no están asignadas ". ¿Cómo podría ser esto?

Agradeceríamos cualquier sugerencia sobre cómo podríamos avanzar. No estamos haciendo nada más que el código C #, y no estamos haciendo nada más que una lectura periódica de https. ¿Qué podemos hacer para mejorar la depuración? (No podemos rastrear nada, ya que la aplicación es eliminada por iOS). Hemos intentado crear una demostración más simple, pero no falla lo suficientemente rápido como para que valga la pena usarla. Si un desarrollador de Novell MonoTouch desea nuestra fuente, podemos proporcionarla sujeta a la confidencialidad obvia.


Gracias a su reproducción, hemos encontrado y corregido un problema muy oscuro en el recolector de basura. Se incluirá en MonoTouch 4.0.2.


Tu preguntaste:

"Las estructuras internas del kernel no pudieron ser asignadas ... ¿Cómo podría ser esto?

Una razón podría ser la fragmentación de la memoria. Para obtener más información sobre este tema, consulte, por ejemplo, Cómo resolver la fragmentación de la memoria . Esto también puede pertenecer a otros recursos internos, como los punteros a archivos. Por lo tanto, el problema solo es visible en los dispositivos con recursos limitados y no en el simulador.

Para encontrar fugas de recursos no obvias, también: ¿Está utilizando el análisis de código estático (FxCop) de Visual Studio? Algunas de las reglas proporcionan sugerencias para liberar recursos de manera explícita, por ejemplo, para llamar a Dispose o sugerir que se implemente la interfaz IDispose.