0

我一直在使用 Instruments 应用程序检查我的应用程序是否存在泄漏。在某些情况下,HUD 面板中的表格视图每秒更新一次。除了每秒(reloadData) _NSArrayl 对象的数量增加一之外,一切正常。如果我将数据源更改为 return(@""); (它们都是文本单元格)然后问题仍然存在(没有变化)。如果我将所有周围的代码删除为:

[myTableView reloadData];

- (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)column row:(int)rowIndex {
   return(@"");
}

(甚至返回零)

问题仍然存在。注释掉 [myTableView reloadData],问题就消失了。每个块都是一个 _NSarrayl,大小为 32 字节,详细信息:

   0 libsystem_c.dylib calloc
   1 libobjc.A.dylib class_createInstance
   2 CoreFoundation __CFAllocateObject2
   3 CoreFoundation +[__NSArrayI __new::]
   4 CoreFoundation -[__NSPlaceholderArray initWithObjects:count:]
   5 CoreFoundation +[NSArray arrayWithObjects:]
   6 AppKit -[NSWindow _runLoopModesForInvalidCursorRectsObserver]
   7 AppKit __-[NSWindow _postInvalidCursorRects]_block_invoke_1
   8 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
   9 CoreFoundation __CFRunLoopDoObservers
  10 CoreFoundation __CFRunLoopRun
  11 CoreFoundation CFRunLoopRunSpecific
  12 HIToolbox RunCurrentEventLoopInMode
  13 HIToolbox ReceiveNextEventCommon
  14 HIToolbox BlockUntilNextEventMatchingListInMode
  15 AppKit _DPSNextEvent
  16 AppKit -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
  17 AppKit -[NSApplication run]
  18 AppKit NSApplicationMain

我注意到这些对象的历史记录中有一个 Autorelease 条目,所以我想知道它是否已被自动释放(保留计数仍为 1)。但是 5 分钟后,没有任何东西释放它们,所以可能自动释放池没有被释放。我不创建任何自动释放池(也不释放任何),而是留下应用程序框架。我应该对自动释放池做些什么吗?

#   Address Category    Event Type  RefCt   Timestamp   Size    Responsible Library Responsible Caller
0   0x100669cf0 __NSArrayI  Malloc  1   00:01.342.634   32  AppKit  -[NSWindow _runLoopModesForInvalidCursorRectsObserver]
1   0x100669cf0 __NSArrayI  Autorelease <null>  00:01.342.636   0   AppKit  -[NSWindow _runLoopModesForInvalidCursorRectsObserver]

任何关于我可能做错了什么的建议将不胜感激。

请注意,1秒更新的情况对于应用程序来说不是“正常情况”,但它可能会发生,然后应用程序设计了很长时间;即不是您运行、退出、再次运行、退出等的应用程序。

它们没有被检测为“泄漏”,但分配计数一直在增加,所以我认为它们在实践中是泄漏(或出现问题)

我没有使用 ARC 而不是“垃圾收集”——只是保留/释放系统,我倾向于使用保留/释放,而我自己的代码只是偶尔使用自动释放,并且与此代码无关。

附加信息:我一直在看着计数增加,只使用 Instruments 应用程序(表格视图位于始终可见的 HUD 中)。但是,如果我将鼠标移到“泄漏”的 tableview 上 - 计数会回到合理的值。在屏幕上稍微移动包含 tableview 的 HUD 窗口,计数会回落,等等。似乎是缺少用户活动导致这种情况发生。我仍然很困惑,但认为这个新的观察可能有助于想法(或者如果有人试图重现它)。

4

2 回答 2

1

代码本身不会泄漏。但是可能发生的是外部自动释放池没有耗尽。这在 AppKit 中是一件棘手的事情:AppKit 运行循环会自动添加一个自动释放池,但只会在它接收到事件(即您移动鼠标)时将其耗尽。

您可以通过激活应用程序并移动鼠标然后再次尝试泄漏来确认这一点。

这意味着,一般来说,在您的自定义非事件驱动回调中添加您自己的自动释放池是一个好主意。一些基本的 Foundation 机制已经为您完成了这项工作(例如,NSTimer 在触发之前为您创建了一个池并在之后将其排出),但并非一切都为您完成。

在这种特殊情况下,您似乎对该特定​​回调没有太多控制权,因此:

1)考虑在运行泄漏之前对您的应用程序进行处理

2) 可能向 Apple 提交错误

于 2012-08-08T23:43:03.947 回答
0

更新和后续问题(抱歉) ** 根据您的建议,我在 [myTableView reloadData] 下方添加了一些内容,以向应用程序发布一个虚拟/无害的消息(看起来比直接发布到相关窗口更安全)。

NSEvent *dummyEvent=[NSEvent mouseEventWithType:NSMouseMoved location:NSMakePoint(0.0,0.0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil eventNumber:0 clickCount:0 pressure:0.0];
[NSApp postEvent:dummyEvent atStart:FALSE];

我的想法是添加在表格视图完成所有内容之后会发生的事情(基本上是当事件队列变空时。这看起来像是用户在做某事。只要不断增加的分配计数不再增加,它似乎就可以工作(按预期移动了一点,但基本稳定)。

但是,我对事件做的不多,并且担心我的“dummyEvent”可能不是无害的,或者将来可能会开始引起问题。有没有更好的方法来实现这一点,或者我应该使用更好的事件(或参数)?

我确实尝试过

NSEvent *dummyEvent=[NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0.0,0.0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:(short)(0) data1:0 data2:0];

但我对此不太信任,因为我没有自定义事件处理程序,并且不确定它最终会在哪里结束。另外,我第一次使用此变体也遇到了地址违规 - 但我想知道这是否是其他事情,因为它没有再次发生。只要我的参数都不会导致崩溃/断言失败或类似情况,我可以看到虚拟鼠标移动是如何无害的。

于 2012-08-09T09:29:29.117 回答