为什么我们的MonoTouch应用程序会破坏垃圾收集器?它并没有内存不足

mj2*_*008 17 memory-management xamarin.ios ios

我们有一个简单的问题,但原因很复杂.我们是经验丰富的开发人员,并且已经对可能导致它的原因进行了大量研究.我们希望MonoTouch开发人员能够与我们合作,以确定人们所面临的常见问题,而且目前还没有解决方案.我们已经为此工作了两个多星期,但未能解决它.

问题是:为什么我们的MonoTouch应用程序在垃圾收集器中崩溃?它并没有内存不足.

情况是我们有一个应用程序定期检查Web服务(可能每5秒).经过一段时间后,内存管理中止失败.这通常在大约一个半小时后发生,但可以是十分钟到一夜之间的任何地方.这种情况发生在我们所有的测试设备上(我们总共有7个测试设备,包括iOS3和iOS4,iPod Touch,iPhone和iPad(1和2).在查看StackOverflow之后,我们在计时器中添加了一个System.Gc.Collect.这改善了一些事情(失败需要更长的时间),但它并没有消失.还有一点值得补充的是,来自iPad的内存日志显示有777个免费模块,我们的应用程序使用了2041个,共有26488个有线页面.由于我们收集了垃圾,并且没有做出与我们之前5秒做的不同的事情,因此内存耗尽似乎很奇怪.

我们升级到MonoTouch 4.0.1,但还没有修复它.

计算器上可能出现的同一个问题的问题,但没有回答它:五六六六九〇五 /四五四五三八三/五四九二四六九/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上的某些区域或边界处理方式不同?

用于GC_allochblk_nth的https://github.com/mono/mono/blob/master/libgc/allchblk.c中的代码表示仅在找到的内存块有效时才调用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开发人员需要我们的源代码,我们可以提供明显的机密性.

Geo*_*ton 13

由于您的复制,我们发现并纠正了垃圾收集器中一个非常模糊的问题.它将包含在MonoTouch 4.0.2中.