连接仪器时 NSActionDispatcher 被垃圾收集
Posted
技术标签:
【中文标题】连接仪器时 NSActionDispatcher 被垃圾收集【英文标题】:NSActionDispatcher is Garbage Collected when Instruments is attached 【发布时间】:2013-01-14 18:40:54 【问题描述】:我正在尝试向我的 ios 应用程序添加一个计时器,为此我使用以下代码:
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace MyNamespace
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
UIWindow window;
public static NavigationController MyNavigationController;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
RectangleF bounds = UIScreen.MainScreen.Bounds;
MyNavigationController = new NavigationController(bounds);
window = new UIWindow (bounds);
window.RootViewController = MyNavigationController;
window.MakeKeyAndVisible ();
return true;
public class NavigationController : UINavigationController
private RectangleF _bounds;
private RectangleF _viewPort;
public NavigationController(RectangleF bounds)
_bounds = bounds;
NavigationBar.BarStyle = UIBarStyle.Black;
public override void ViewDidLoad()
base.ViewDidLoad();
_viewPort = new RectangleF(_bounds.Location, new SizeF(_bounds.Width, _bounds.Height - NavigationBar.Frame.Height));
ShowFirstView(); // Default to showing FirstViewController
public void ShowFirstView()
PushViewController(new FirstViewController(_viewPort), true);
public void ShowSecondView()
PushViewController(new SecondViewController(_viewPort), true);
public class FirstViewController : UIViewController
public FirstViewController(RectangleF bounds)
// Empty view
View = new UIView(bounds);
View.BackgroundColor = UIColor.White;
Title = "First View";
// Simple button to navigate to next view
UIButton button = UIButton.FromType(UIButtonType.RoundedRect);
button.Frame = new RectangleF(10,10,300,30);
button.SetTitle("Show next view", UIControlState.Normal);
button.TouchUpInside += (sender, e) => AppDelegate.MyNavigationController.ShowSecondView(); ;
View.AddSubview(button);
public class SecondViewController : UIViewController
private NSTimer _timer;
public SecondViewController(RectangleF bounds)
// Empty View
View = new UIView(bounds);
View.BackgroundColor = UIColor.Blue;
Title = "Second View";
// Create timer
_timer = NSTimer.CreateRepeatingScheduledTimer(2f, delegate Console.WriteLine("Timer Fired"); );
当我在模拟器中运行此代码时,它按预期工作,每 2 秒将“Timer Fired”写入控制台。
但是,当我附加 Apple Instruments,特别是 Allocations Instrument 时,Main.cs
中的UIApplication.Main (args, null, "AppDelegate");
会引发异常
从 Objective-c 调用的选择器在已被 GC 处理的 MonoTouch.Foundation.NSActionDispatcher (0x10AA2D50) 类型的托管对象上调用
堆栈跟踪:
System.Exception: Selector invoked from objective-c on a managed object of type MonoTouch.Foundation.NSActionDispatcher (0x14FB5AC0) that has been GC'ed ---> System.Exception: No constructor found for MonoTouch.Foundation.NSActionDispatcher::.ctor(System.IntPtr)
at System.Activator.CreateInstance (System.Type type, BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x000f1] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:280
at System.Activator.CreateInstance (System.Type type, System.Object[] args, System.Object[] activationAttributes) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:234
at System.Activator.CreateInstance (System.Type type, System.Object[] args) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:229
at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x0000d] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:231
--- End of inner exception stack trace ---
at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x00045] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:236
at MonoTouch.ObjCRuntime.Runtime.GetNSObject (IntPtr ptr) [0x0001f] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:280
at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (IntPtr ptr) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:297
at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime:GetNSObjectWrapped (intptr)
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at MyNamescape.Application.Main (System.String[] args) [0x00000] in Main.cs:17
注意事项:
应用在模拟器中正常运行,正常情况下(无仪器) 该问题仅在分配工具对其进行监控时出现。如果使用其他仪器(例如泄漏),则不会出现问题。 仅当我在设置计时器之前连接分配工具时才会出现此问题。如果我在设置计时器后附加分配工具,那么它会按预期工作。 分配工具适用于我的应用程序的其他视图控制器 我在此上下文或 MonoTouch 中找不到有关NSActionDispatcher
的太多信息
我目前无法在物理设备上进行测试。
所以我不确定这是否是分配工具的问题,或者我的代码中是否存在严重错误。非常感谢您对此问题的任何建议。
编辑:我已更新代码以显示导致问题的最简单的完整应用程序用例。 (我已根据 PouPou 关于不必要使用线程的评论更新了我的计时器代码)
更新(2013 年 1 月 17 日):我使用 iPad 和 iPhone 模拟器 5.0、5.1 和 6.0 版进行了尝试,都产生了相同的结果。
更新(2013 年 1 月 18 日):根据 Rolf 的请求添加了本机堆栈帧。
2013-01-18 13:28:47.579 TestTimer[12196:c07] at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x00045] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:236
at MonoTouch.ObjCRuntime.Runtime.GetNSObject (IntPtr ptr) [0x0001f] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:280
at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (IntPtr ptr) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:297
at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime:GetNSObjectWrapped (intptr)
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at MyNamescape.Application.Main (System.String[] args) [0x00000] in Main.cs:16
2013-01-18 13:28:47.623 TestTimer[12196:c07] 0 TestTimer 0x00093a22 mono_handle_exception_internal_first_pass + 3058
1 TestTimer 0x00095102 mono_handle_exception_internal + 1602
2 TestTimer 0x00095c4f mono_handle_exception + 47
3 TestTimer 0x000dda72 mono_x86_throw_exception + 306
4 ??? 0x0b3e0f8f 0x0 + 188616591
at MonoTouch.ObjCRuntime.Runtime.GetNSObject (intptr) [0x0001f] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:280
at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (intptr) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:297
at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (intptr) <IL 0x00017, 0x00094>
8 TestTimer 0x00224873 get_managed_object_for_ptr + 115
9 TestTimer 0x00229700 monotouch_trampoline + 448
10 Foundation 0x019b9b90 __NSFireTimer + 97
11 CoreFoundation 0x01315376 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
12 CoreFoundation 0x01314e06 __CFRunLoopDoTimer + 534
13 CoreFoundation 0x012fca82 __CFRunLoopRun + 1810
14 CoreFoundation 0x012fbf44 CFRunLoopRunSpecific + 276
15 CoreFoundation 0x012fbe1b CFRunLoopRunInMode + 123
16 GraphicsServices 0x04b807e3 GSEventRunModal + 88
17 GraphicsServices 0x04b80668 GSEventRun + 104
18 UIKit 0x0273965c UIApplicationMain + 1211
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x00056, 0x001f5>
at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at MyNamescape.Application.Main (string[]) [0x00000] in Main.cs:16
at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00049, 0x0014e>
23 TestTimer 0x00010252 mono_jit_runtime_invoke + 722
24 TestTimer 0x0017478e mono_runtime_invoke + 126
25 TestTimer 0x00178be4 mono_runtime_exec_main + 420
26 TestTimer 0x00178f55 mono_runtime_run_main + 725
27 TestTimer 0x0006ba65 mono_jit_exec + 149
28 TestTimer 0x0021f65d main + 2013
29 TestTimer 0x00003125 start + 53
【问题讨论】:
有什么理由使用Thread
吗?因为计时器本身可以每两秒在控制台上打印一次?也不需要在该线程上创建NSAutoreleasePool
(MonoTouch 从 5.4 甚至在此之前 就已经为您完成了)。 OTOH 我很确定 Instrument 会捕获(并处理)它们。最后我不确定你为什么从那里调用runloop(而不是让线程或时间完成并再次被调用)。如果您可以编辑您的问题并添加更多上下文,那么我们应该能够提出一些有用的答案:-)
@poupou 不,似乎没有任何理由使用另一个Thread
。这是因为我从我发现的一个示例中提取了NSTimer
代码,这似乎是在做一些更复杂的事情。因此,感谢您在简化其使用方面的帮助。我已更新我的代码以删除 Thread
创建。不幸的是,错误仍然存在,尽管它发生的点已经移动到 Main.cs(因为计时器在不同的线程上)。我添加了完整的简化用例来重现该问题。我希望你能启发我。感谢您的帮助。
我尝试了你的测试用例,但它对我来说效果很好(但我无法像你看起来那样附加到正在运行的进程,应用程序的进程没有出现在列表中正在运行的进程。我必须选择二进制文件并使用 Instruments 启动应用程序)。您使用哪个模拟器(5.1/6.0 iPad/iPhone)也有关系吗?
@RolfBjarneKvinge 我试过 iPad 和 iPhone 的 5.0、5.1 和 6.0 版本,都产生同样的问题。我没有在选择目标中看到我的二进制文件,所以我必须选择附加到进程。感谢您对此进行调查。
您可以手动选择目标:首先使用 MonoDevelop 运行您的项目,然后打开终端并执行 ps aux | grep debugtrack
- 这将显示应用程序的路径。打开 Instruments,然后选择 Target -> 选择 Target 并导航到 .app 路径。如果您现在开始分析,是否有任何变化(因为它会从应用程序启动的一开始就进行分析)?
【参考方案1】:
我(最终)发现这是 MonoTouch 中的一个错误(仪器拦截了保留/释放方法,这使 MonoTouch 感到困惑)。该错误已修复,将包含在下一个稳定版本(6.0.9)中。
【讨论】:
感谢 Rolf 的所有帮助,非常感谢。以上是关于连接仪器时 NSActionDispatcher 被垃圾收集的主要内容,如果未能解决你的问题,请参考以下文章