NSTableView reloadData泄漏内存

时间:2012-08-08 23:30:31

标签: macos memory-leaks nstableview nsautoreleasepool

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

[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而不是“垃圾收集” - 只是保留/释放系统而且我倾向于使用保留/释放,而我自己的代码偶尔会使用自动释放而无法使用此代码。

附加信息:我一直在看着计数增加,只使用了仪器应用程序(tableview是在一个始终可见的HUD中)。但是,如果我是将鼠标移到“漏水”的桌面视图上 - 计数会回落到合理的状态。在屏幕上稍微移动包含tableview的HUD窗口,然后计数向下,等等。似乎缺少允许这种情况发生的用户活动。我仍然感到难过,但认为这个新的观察可能有助于提出想法(或者如果有人试图重现它)。

2 个答案:

答案 0 :(得分:0)

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

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

这意味着,通常,在自定义非事件驱动的回调中添加自己的自动释放池是个好主意。一些基本的基础机制已经为你做了(例如NSTimer在开火之前为你创建一个游泳池并在之后消耗它)但不是一切都为你做。

在这种特殊情况下,您似乎无法控制该特定回调,因此:

1)考虑在运行泄漏之前勾选应用程序

2)可能会向Apple提交错误

答案 1 :(得分: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];

我的想法是添加一些在表视图具有锥形内容之后会发生的事情(基本上当事件队列变空时。这看起来像用户正在做的事情。它似乎工作在不断增加的分配计数不再增加(按预期移动一点但基本稳定)。

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

我确实尝试了

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];

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