我一直在为以下泄漏问题苦苦挣扎。通过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时。
这里是来自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
是在applicationDidFinishLaunching
中进行NSMutableArray
的分配和初始化,并在dealloc
方法中释放。
在NewMessageWindowController
中,我使用以下方式通知应用程序委托窗口即将关闭,不再需要保留控制器:
- (void)windowWillClose:(NSNotification *)notification {
[AppDelegate windowControllerDidFinish:self];
}
应用程序委托的方法看起来像这样:
- (void)windowControllerDidFinish:(NSWindowController *)controller {
[windowControllers removeObject:controller];
}
记录数组在窗口关闭前和关闭后的状态是我所期望的。控制器在窗口关闭之前存在,当窗口关闭时被移除。
Instruments会在我关闭窗口时检测到内存泄漏。在窗口打开时,一切似乎都正常。值得注意的是,dealloc按预期在NewMessageWindowController中被调用。泄漏并没有报告控制器本身是问题,而是一个NSCFString对象泄漏了,它只是源自上面的代码。
Build and Analyze没有发现任何问题,并且我相信我在创建/显示窗口控制器/窗口的代码块中的内存管理是正确的。
奇怪的是,只有在使用键盘关闭窗口时才会出现泄漏。如果我点击红色关闭按钮,Instruments就不会检测到任何问题。
最后,Instruments并不总是显示该代码块负责。在这些情况下,Instruments没有引用我的任何代码 - 它似乎全部来自AppKit。同样,这只发生在我使用键盘关闭窗口(cmd-w)的情况下。
有什么想法吗?