MonoTouch不稳定性仍在继续:托管内存分配器崩溃

Mik*_*ike 8 iphone-sdk-3.0 xamarin.ios ios4

简而言之:我可以分配大量非托管内存,但尝试在托管内存中分配相同数量(或更少)会导致GC_remap中的MonoTouch崩溃(下面的callstack).

细节:

我将谈谈上面描述的行为的一个例子.我的应用程序偶尔会分配一个2.5MB大小的托管内存(使用新的byte []),并且它经常在我的iPhone4上死掉,下面粘贴了callstack(即分配期间的mprotect错误).我没有比单个函数调用更长时间地引用这些2.5MB块.

MonoTouch的人说'mprotect errno 12'意味着你已经耗尽了设备上的内存,但问题是,我的应用程序可以使用大量内存.我可以在我的应用启动时分配0MB,10MB200MB非托管内存(使用Marshal.AllocHGlobal),每帧都触摸它,它对我的​​应用程序的行为或此mprotect错误的频率没有区别.

一些笔记

  • GC.TotalMemory告诉我,我的应用程序一直处于3MB5MB的托管内存使用量之间.
  • 我在我的应用程序中有其他地方,我正在分配更大的非托管内存块,它永远不会在那里崩溃.我创建了压力测试,加载4MB(非托管)纹理数据,将其交给GL,并在每一帧绘制它,应用程序坚如磐石,直到我开始要求大块的托管内存.
  • 除非我自己调用GC.Collect,否则GC.CollectionCount几乎没有变化.
  • MonoTouch 3.2.3以及MonoTouch 4.0也会出现同样的情况.
  • 所有测试设备(iPhone 3G,3GS,4,iPad,iPad2)都会出现同样的情况.
  • 在发布版本和调试版本中也会发生相同的行为,尽管调试版本会更频繁地发生.

引发崩溃的方法

  • 如果我创建一个循环调用GC.Collect,然后休眠1ms,这会使崩溃更快发生(即,如果我在调试版本中,几乎立即).
  • 使用某些.NET功能(如WebRequest)也会导致此崩溃.我只能假设它在那里的某个地方分配大块的托管内存.

崩溃的方式

有两种方法可以减少崩溃的频率或完全修复它:

  1. 如果我预先分配2.5MB大小的托管内存,然后在应用程序的生命周期中保留它,那么就不会崩溃.
  2. 如果我在做任何事情之前将2.5MB的内存固定,那么这似乎有所帮助.

结论/问题

由于这个问题,我们尚未在我们的应用程序中实现完全稳定性.这个崩溃(总是在GC_remap中)发生在我们整个应用程序的随机分配中(我在这里的2.5MB示例就是我选择隔离和重新编写的那个).

问题:

  1. 我根本不信任托管分配器吗?
  2. 为什么我可以分配200MB的非托管内存,但是当我要求2.5MB时,托管分配器会死掉?(注意:即使我没有分配200MB的非托管内存,当我要求2.5MB时也会死掉).
  3. 为什么如果我在应用程序的生命周期内占用2.5MB这个应用程序是完全正常的,但是如果我把它还给系统(并调用GC.Collect)并要求另外2.5MB以后,那么崩溃就更糟了!如果这确实是一个内存不足的情况,那么给系统回馈2.5MB是不是更好呢?

我们甚至可以使用MonoTouch吗?

我的团队正在认真考虑放弃MonoTouch用于我们的产品,因为我们无法让它稳定可靠.

我们也无法从MonoTouch团队获得堆栈溢出,在Novell网站上提交错误,或直接通过电子邮件发送MonoTouch的支持电子邮件.我们已将(托管和非托管)内存使用量减少到荒谬的低点,但由于此问题,应用程序仍然崩溃.

在短期内,我想到的唯一解决方法是在启动时分配一大块内存(2-5MB),将其设为PIN,以便垃圾收集器永远不会触及它,并编写我自己的分配器来分配部分内存.这个内存块根据需要阻止我的应用程序.但如果这是MonoTouch下可能的最佳解决方案,那么只要我能从MonoTouch获得逃逸速度,我就会想要我的钱.

...

Mprotect failed at 0xaa00000 (length 3801088) with errno 12
Stacktrace:

  at MyApp.GameScreen/VerifyPictureDialog.StoreBasePictureData () [0x00000] in /Users/dussault/s/MyApp/Main/Src/PhotoScreens.cs:428
  at MyApp.GameScreen/VerifyPictureDialog.ApplyFilters (bool) [0x0004b] in /Users/dussault/s/MyApp/Main/Src/PhotoScreens.cs:640
  at MyApp.GameScreen/VerifyPictureDialog.Simulate (single) [0x00077] in /Users/dussault/s/MyApp/Main/Src/PhotoScreens.cs:477
  at MyApp.BaseWindow.Simulate (single) [0x00007] in /Users/dussault/s/MyApp/Main/Src/BaseWindow.cs:56
  at MyApp.BaseWindow.Simulate (single) [0x00007] in /Users/dussault/s/MyApp/Main/Src/BaseWindow.cs:56
  at MyApp.GameScreen.Simulate (single) [0x00238] in /Users/dussault/s/MyApp/Main/Src/GameScreen.cs:3114
  at MyApp.BaseWindow.Simulate (single) [0x00007] in /Users/dussault/s/MyApp/Main/Src/BaseWindow.cs:56
  at MyApp.WindowMgr.Simulate (single) [0x0002f] in /Users/dussault/s/MyApp/Main/Src/WindowMgr.cs:126
  at MyApp.Game1.Update (Microsoft.Xna.Framework.GameTime) [0x0010f] in /Users/dussault/s/MyApp/Main/Src/Game1.cs:1194
  at Microsoft.Xna.Framework.Game.DispatchUpdate (Microsoft.Xna.Framework.GameTime) [0x00000] in /Users/dussault/s/MyApp/Main/Src/XNA-Emulation/GraphicsDevice.cs:531
  at MyApp_iOS.EAGLView.OnUpdateFrame () [0x00050] in /Users/dussault/s/MyApp/Main/Src/iOS/EAGLView.cs:310
  at MyApp_iOS.EAGLView.SimulateAndRender () [0x0000a] in /Users/dussault/s/MyApp/Main/Src/iOS/EAGLView.cs:279
  at MyApp_iOS.EAGLView.MainLoopTimerCallback () [0x00006] in /Users/dussault/s/MyApp/Main/Src/iOS/EAGLView.cs:231
  at MonoTouch.Foundation.NSActionDispatcher.Apply () <0x0002b>
  at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0xffffffff>
  at MonoTouch.UIKit.UIApplication.Main (string[],string,string) <0x000cf>
  at MonoTouch.UIKit.UIApplication.Main (string[]) <0x00023>
  at MyApp_iOS.Application.Main (string[]) [0x00000] in /Users/dussault/s/MyApp/Main/Src/iOS/Main.cs:57
  at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0xffffffff>

Native stacktrace:

    0   MyApp_iOS                           0x00af1b48 mono_handle_native_sigsegv + 412
    1   MyApp_iOS                           0x00b1c66c sigabrt_signal_handler + 148
    2   libSystem.B.dylib                   0x33bd3ddf _sigtramp + 42
    3   libSystem.B.dylib                   0x33bd52cb kill + 10
    4   libSystem.B.dylib                   0x33bd52bd raise + 16
    5   libSystem.B.dylib                   0x33be9d79 abort + 56
    6   MyApp_iOS                           0x00c74378 GC_remap + 200
    7   MyApp_iOS                           0x00c62c04 GC_allochblk_nth + 1536
    8   MyApp_iOS                           0x00c625b4 GC_allochblk + 96
    9   MyApp_iOS                           0x00c6bf6c GC_alloc_large + 132
    10  MyApp_iOS                           0x00c6c5e8 GC_generic_malloc + 324
    11  MyApp_iOS                           0x00c6c8c8 GC_malloc_atomic + 332
    12  MyApp_iOS                           0x00bd8e88 mono_object_allocate_ptrfree + 64
    13  MyApp_iOS                           0x00bd8ff4 mono_array_new_specific + 148
    14  MyApp_iOS                           0x009173f4 wrapper_managed_to_native_object___icall_wrapper_mono_array_new_specific_intptr_int + 68
    15  MyApp_iOS                           0x002cd880 MyApp_GameScreen_VerifyPictureDialog_ApplyFilters_bool + 628
    16  MyApp_iOS                           0x002cbffc MyApp_GameScreen_VerifyPictureDialog_Simulate_single + 768
    17  MyApp_iOS                           0x002ef9d0 MyApp_BaseWindow_Simulate_single + 280
    18  MyApp_iOS                           0x002ef9d0 MyApp_BaseWindow_Simulate_single + 280
    19  MyApp_iOS                           0x002a71fc MyApp_GameScreen_Simulate_single + 2736
    20  MyApp_iOS                           0x002ef9d0 MyApp_BaseWindow_Simulate_single + 280
    21  MyApp_iOS                           0x0038068c MyApp_WindowMgr_Simulate_single + 376
    22  MyApp_iOS                           0x0027f798 MyApp_Game1_Update_Microsoft_Xna_Framework_GameTime + 1992
    23  MyApp_iOS                           0x0039afc8 Microsoft_Xna_Framework_Game_DispatchUpdate_Microsoft_Xna_Framework_GameTime + 148
    24  MyApp_iOS                           0x0026ec10 MyApp_iOS_EAGLView_OnUpdateFrame + 716
    25  MyApp_iOS                           0x0026e8cc MyApp_iOS_EAGLView_SimulateAndRender + 196
    26  MyApp_iOS                           0x0026e1cc MyApp_iOS_EAGLView_MainLoopTimerCallback + 296
    27  MyApp_iOS                           0x009a7dfc MonoTouch_Foundation_NSActionDispatcher_Apply + 44
    28  MyApp_iOS                           0x00912540 wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200
    29  MyApp_iOS                           0x00acc9c4 mono_jit_runtime_invoke + 2800
    30  MyApp_iOS                           0x00bd3ea4 mono_runtime_invoke + 140
    31  MyApp_iOS                           0x00c7d214 monotouch_trampoline + 2840
    32  Foundation                          0x3363b469 __NSFireTimer + 136
    33  CoreFoundation                      0x33a770a3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
    34  CoreFoundation                      0x33a76b5b __CFRunLoopDoTimer + 850
    35  CoreFoundation                      0x33a481b5 __CFRunLoopRun + 1088
    36  CoreFoundation                      0x33a47c87 CFRunLoopRunSpecific + 230
    37  CoreFoundation                      0x33a47b8f CFRunLoopRunInMode + 58
    38  GraphicsServices                    0x33b0e4ab GSEventRunModal + 114
    39  GraphicsServices                    0x33b0e557 GSEventRun + 62
    40  UIKit                               0x32099329 -[UIApplication _run] + 412
    41  UIKit                               0x32096e93 UIApplicationMain + 670
    42  MyApp_iOS                           0x009d484c wrapper_managed_to_native_MonoTouch_UIKit_UIApplication_UIApplicationMain_int_string___intptr_intptr + 240
    43  MyApp_iOS                           0x009b4c00 MonoTouch_UIKit_UIApplication_Main_string__ + 36
    44  MyApp_iOS                           0x00269694 MyApp_iOS_Application_Main_string__ + 128
    45  MyApp_iOS                           0x00912540 wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200
    46  MyApp_iOS                           0x00acc9c4 mono_jit_runtime_invoke + 2800
    47  MyApp_iOS                           0x00bd3ea4 mono_runtime_invoke + 140
    48  MyApp_iOS                           0x00bd6f3c mono_runtime_exec_main + 784
    49  MyApp_iOS                           0x00bd5f6c mono_runtime_run_main + 1048
    50  MyApp_iOS                           0x00ad7940 mono_jit_exec + 216
    51  MyApp_iOS                           0x00ac2e38 main + 3536
    52  MyApp_iOS                           0x000133a0 start + 52

Debug info from gdb:


=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
Run Code Online (Sandbox Code Playgroud)

mig*_*aza 1

Darwin 内核过度使用内存。

这意味着,如果您请求 200 兆内存,即使它们不可用,您也会得到它们,只要您实际上不消耗内存,您的应用程序就会正常运行。

只有当您实际写入该页面时,该页面才会分配给您的进程。

正确的测试需要您分配内存,然后填充已使用的内存,这就是为什么您可能会觉得您可以分配 200 兆内存,即使您可能没有。

一个简单的程序将向您展示这一点:尝试分配 500 兆,操作系统会说“是的,您明白了”,但没有具有这种内存的 iPhone。

示例测试用例将有助于显示问题所在。