【问题标题】:Memory Leak with NSWindowController's showWindow:NSWindowController 的 showWindow 导致内存泄漏:
【发布时间】:2011-05-25 14:41:18
【问题描述】:

我一直在为以下泄漏而苦苦挣扎。我通过 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 是在applicationDidFinishLaunching 中分配/初始化的NSMutableArray,并在dealloc 方法中释放。

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

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

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

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

在之前和之后记录数组是我所期望的。控制器在窗口关闭之前就在里面,当窗口关闭时它就被移除了。

当我关闭窗户时,仪器会发现泄漏。虽然它是开放的,但一切似乎都很好。值得注意的是,在 NewMessageWindowController 中按预期调用了 dealloc。 Leaks 并未将控制器本身报告为问题,而是泄漏的对象是一个 NSCFString,它只是源自上面的代码。

Build and Analyze 没有得到任何东西,我很确定我的内存管理在创建/显示窗口控制器/窗口的代码块上很好。

奇怪的是,如果我使用键盘关闭窗口,只会出现泄漏。如果我点击红色的关闭按钮,Instruments 不会拾取任何东西。

最后,Instruments 并不总是表明该代码块是负责的。在这些情况下,我的代码都没有在 Instruments 中被引用——它似乎都是 AppKit。同样,这仅在我使用键盘关闭窗口时(cmd-w)。

有什么想法吗?

【问题讨论】:

    标签: objective-c cocoa memory-leaks nswindow nswindowcontroller


    【解决方案1】:

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

    【讨论】:

    • Dealloc 在使用键盘或鼠标时确实在 NSWindowController 中被调用。
    • Instruments 是否说 NewMessageWindowController 是对象泄漏?如果是这种情况并且你看到对象被释放,这意味着你有一个错误的泄漏。稍等片刻后尝试重新运行泄漏扫描;泄漏可能会消失。如果对象明显被释放,我不会担心这个泄漏。
    • Instruments 将 NSCFString 显示为泄漏对象,它只是源自 showWindow 调用(或者 Instruments 是这么说的)。
    • 我在问题中添加了一个屏幕截图,显示了仪器中发生的事情 (files.thermoglobalnuclearwar.com/Instruments.png)
    • 奇数。这看起来像是在 Kit 事件处理代码中的深处。似乎没有任何事情可以干扰这种内存管理。如果重新取样,泄漏是否会继续存在?我倾向于认为这是暂时的或虚假的泄漏。
    【解决方案2】:

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

    【讨论】:

    • 我看到使用键盘或鼠标在 NewMessageWindowController 上调用了 dealloc 以关闭其窗口。
    猜你喜欢
    • 2015-07-06
    • 2014-06-07
    • 2013-11-20
    • 2011-10-28
    • 2016-01-18
    • 2012-12-13
    • 1970-01-01
    • 2011-01-08
    • 2011-02-01
    相关资源
    最近更新 更多