NSWindowController 的 showWindow 内存泄漏:

发布于 2024-11-09 16:00:49 字数 3403 浏览 2 评论 0原文

我已经为以下泄漏而苦苦挣扎了一段时间。我通过 Instruments 将其范围缩小到以下代码块:

- (NewMessageWindowController *)showNewMessageWindowWithRecipients:(NSArray *)recipients {

    NewMessageWindowController * newMessageWindowController = [[NewMessageWindowController alloc] init];
    [newMessageWindowController showWindow:self]; // 100% on this line.
    [newMessageWindowController.toField setStringValue:[recipients componentsJoinedByString:@","]];
    [newMessageWindowController.messageView becomeFirstResponder];
    [windowControllers addObject:newMessageWindowController];
    [newMessageWindowController release];

    return newMessageWindowController;
}

该块的调用方式如下:

[AppDelegate showNewMessageWindowWithRecipients:[NSArray arrayWithObject:recipient]];

其中 recipient 只是一个 NSString。

这是来自仪器的回溯:

  30 Friendz start
  29 AppKit NSApplicationMain
  28 AppKit -[NSApplication run]
  27 AppKit -[NSApplication sendEvent:]
  26 AppKit -[NSWindow sendEvent:]
  25 AppKit -[NSWindow keyDown:]
  24 AppKit forwardMethod
  23 Friendz -[FriendzAppDelegate showNewMessageWindowWithRecipients:] /Path/To/FriendzAppDelegate.m:226
  22 AppKit -[NSWindowController showWindow:]
  21 AppKit -[NSWindow makeKeyAndOrderFront:]
  20 AppKit -[NSWindow _makeKeyRegardlessOfVisibility]
  19 AppKit -[NSWindow _changeKeyAndMainLimitedOK:]
  18 AppKit -[NSWindow becomeKeyWindow]
  17 AppKit _NXResetCursorState
  16 AppKit +[NSEvent _discardCursorEventsForWindowNumber:criteria:]
  15 HIToolbox FlushSpecificEventsFromQueue
  14 HIToolbox PullEventsFromWindowServer
  13 HIToolbox PullEventsFromWindowServerOnConnection(unsigned int, unsigned char)
  12 HIToolbox ConvertPlatformEventRecordAndPostWithOptions(__CGEvent*, _CGSEventRecord const*, short, unsigned char, unsigned char)
  11 HIToolbox PostEventToQueueInternal
  10 HIToolbox _NotifyEventLoopObservers
   9 HIToolbox KeyEventPostedObserver
   8 HIToolbox TSMProcessRawKeyCode
   7 HIToolbox TSMTranslateKeyEvent
   6 HIToolbox GetDataFromUCHRForEvent
   5 HIToolbox ConvertEventUniCharsToCharCodes
   4 HIToolbox utGetInputSourceScriptInfo
   3 CoreFoundation CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes
   2 CoreFoundation CFStringCreateWithCStringNoCopy
   1 CoreFoundation __CFStringCreateImmutableFunnel3
   0 CoreFoundation _CFRuntimeCreateInstance

windowControllers 是一个 NSMutableArrayapplicationDidFinishLaunching 中分配/初始化并在 dealloc 中释放代码>方法。

NewMessageWindowController 中,我使用以下代码来通知应用程序委托窗口即将关闭,并且不再需要保留控制器:

- (void)windowWillClose:(NSNotification *)notification {
    [AppDelegate windowControllerDidFinish:self];
}

应用程序委托的方法如下所示:

- (void)windowControllerDidFinish:(NSWindowController *)controller {
    [windowControllers removeObject:controller];
}

之前记录数组之后就是我期望的样子。控制器在窗口关闭之前就在那里,当窗口关闭时它就会被删除。

当我关闭窗户时,仪器检测到泄漏。虽然它是开放的,但一切似乎都很好。值得注意的是,dealloc 正在按预期在 NewMessageWindowController 中被调用。 Leaks 不会将控制器本身报告为问题,相反,泄漏的对象是 NSCFString,它只是源于上面的代码。

构建和分析没有拾取任何内容,并且我很确定我的内存管理在创建/显示窗口控制器/窗口的代码块上没有问题。

奇怪的是,只有使用键盘关闭窗口时才会出现泄漏。如果我单击红色关闭按钮,仪器不会拾取任何内容。

最后,Instruments 并不总是显示负责的代码块。在这些情况下,Instruments 中没有引用我的任何代码 - 它似乎都是 AppKit。同样,只有当我使用键盘关闭窗口(cmd-w)时才会出现这种情况。

有什么想法吗?

I've been struggling with the following leak for a while now. I've narrowed it down through Instruments to the following block of code:

- (NewMessageWindowController *)showNewMessageWindowWithRecipients:(NSArray *)recipients {

    NewMessageWindowController * newMessageWindowController = [[NewMessageWindowController alloc] init];
    [newMessageWindowController showWindow:self]; // 100% on this line.
    [newMessageWindowController.toField setStringValue:[recipients componentsJoinedByString:@","]];
    [newMessageWindowController.messageView becomeFirstResponder];
    [windowControllers addObject:newMessageWindowController];
    [newMessageWindowController release];

    return newMessageWindowController;
}

The block is called like this:

[AppDelegate showNewMessageWindowWithRecipients:[NSArray arrayWithObject:recipient]];

Where recipient is just an NSString.

And here is the backtrace from instruments:

  30 Friendz start
  29 AppKit NSApplicationMain
  28 AppKit -[NSApplication run]
  27 AppKit -[NSApplication sendEvent:]
  26 AppKit -[NSWindow sendEvent:]
  25 AppKit -[NSWindow keyDown:]
  24 AppKit forwardMethod
  23 Friendz -[FriendzAppDelegate showNewMessageWindowWithRecipients:] /Path/To/FriendzAppDelegate.m:226
  22 AppKit -[NSWindowController showWindow:]
  21 AppKit -[NSWindow makeKeyAndOrderFront:]
  20 AppKit -[NSWindow _makeKeyRegardlessOfVisibility]
  19 AppKit -[NSWindow _changeKeyAndMainLimitedOK:]
  18 AppKit -[NSWindow becomeKeyWindow]
  17 AppKit _NXResetCursorState
  16 AppKit +[NSEvent _discardCursorEventsForWindowNumber:criteria:]
  15 HIToolbox FlushSpecificEventsFromQueue
  14 HIToolbox PullEventsFromWindowServer
  13 HIToolbox PullEventsFromWindowServerOnConnection(unsigned int, unsigned char)
  12 HIToolbox ConvertPlatformEventRecordAndPostWithOptions(__CGEvent*, _CGSEventRecord const*, short, unsigned char, unsigned char)
  11 HIToolbox PostEventToQueueInternal
  10 HIToolbox _NotifyEventLoopObservers
   9 HIToolbox KeyEventPostedObserver
   8 HIToolbox TSMProcessRawKeyCode
   7 HIToolbox TSMTranslateKeyEvent
   6 HIToolbox GetDataFromUCHRForEvent
   5 HIToolbox ConvertEventUniCharsToCharCodes
   4 HIToolbox utGetInputSourceScriptInfo
   3 CoreFoundation CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes
   2 CoreFoundation CFStringCreateWithCStringNoCopy
   1 CoreFoundation __CFStringCreateImmutableFunnel3
   0 CoreFoundation _CFRuntimeCreateInstance

windowControllers is an NSMutableArray alloc/init'ed in applicationDidFinishLaunching and released in the dealloc method.

In the NewMessageWindowController, I use the following to notify the app delegate that the window is about to close and there's no need to retain the controller any more:

- (void)windowWillClose:(NSNotification *)notification {
    [AppDelegate windowControllerDidFinish:self];
}

The app delegate's method looks like this:

- (void)windowControllerDidFinish:(NSWindowController *)controller {
    [windowControllers removeObject:controller];
}

Logging the array before and after is how I expect it to be. The controller is in there before the window closes, it's removed when the window has closed.

Instruments picks up the leak when I close the window. Whilst it's open, everything appears to be fine. It's worth noting that dealloc is being called in the NewMessageWindowController as expected. Leaks isn't reporting the controller itself as the problem, instead, the object that's leaking is a NSCFString, it just originates from the code above.

Build and Analyze isn't picking anything up, and I'm pretty sure my memory management is fine on the block of code which creates / shows the window controller / window.

What's weird is, there is only a leak if I use the keyboard to close the window. If I click the click the red close button, Instruments doesn't pick anything up.

Finally, Instruments doesn't always show that block of code to be responsible. In those instances, none of my code is referenced in Instruments - it appears to be all AppKit. Again, this is only if I use the keyboard to close a window (cmd-w).

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不羁少年 2024-11-16 16:00:49

在这种情况下我要做的是,使用 Xcode4 中的 Instruments 版本,配置分配工具来记录保留/释放事件。这应该向您展示,对于这个特定的控制器,为什么它的保留计数不会为零。请注意,对于基于鼠标和基于键盘的关闭,可能会执行不同的代码路径。

What I would do in this case is, using the version of Instruments in Xcode4, configure the allocations instrument to record retain / release events. That should show you, for this particular controller, why it's retain count is not going to zero. Note that there is likely to be a different codepath executed for a mouse-based and keyboard-based close.

你的笑 2024-11-16 16:00:49

这是因为当对象被“销毁”时,您不能指望可靠地调用 dealloc - 可能由于某种原因使用键盘比单击 X 更不可能导致立即调用 dealloc?

Is this because you can't count on dealloc to be reliably called when an object is "destroyed" - it could be that using the keyboard for some reason is less likely to result in an immediate call to dealloc than clicking on the X?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文