为什么此简单的NSWindow创建代码在ARC下关闭时触发自动释放池崩溃? [英] Why does this simple NSWindow creation code trigger an autorelease pool crash on shutdown under ARC?

查看:245
本文介绍了为什么此简单的NSWindow创建代码在ARC下关闭时触发自动释放池崩溃?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在关机时遇到自动释放池崩溃的问题,我将其简化为下面的小测试用例,它只是创建一个窗口,然后将其关闭.如果取消了-fobjc-arc标志,崩溃将消失.在OS X 10.8.2,Clang 4.1(421.11.66)上运行.我希望对ARC有更深入了解的人能启发我这里发生的事情-运行带有僵尸对象的程序显示,正是NSWindow对象被释放了太多次,或者保留得不够多,但是我以为ARC应该负责所有这一切?

I am having an issue with an autorelease pool crash on shutdown which I've reduced to the small test case below that simply creates a window and then closes it. The crash disappears if the -fobjc-arc flag is taken away. Running on OS X 10.8.2, Clang 4.1 (421.11.66). I am hoping that someone with a more in depth understanding of ARC can enlighten me as to what is going on here - running with zombie objects on shows that it is the NSWindow object that is getting released too many times, or not retained enough, but I thought ARC was meant to take care of all this?

堆栈跟踪为:

0   libobjc.A.dylib                 0x00007fff8fad4f5e objc_release + 14
1   libobjc.A.dylib                 0x00007fff8fad4230 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 464
2   com.apple.CoreFoundation        0x00007fff99d22342 _CFAutoreleasePoolPop + 34
3   com.apple.Foundation            0x00007fff936e84fa -[NSAutoreleasePool drain] + 154
4   com.apple.Foundation            0x00007fff936effa0 _NSAppleEventManagerGenericHandler + 125
5   com.apple.AE                    0x00007fff93a5ab48 aeDispatchAppleEvent(AEDesc const*, AEDesc*, unsigned int, unsigned char*) + 307
6   com.apple.AE                    0x00007fff93a5a9a9 dispatchEventAndSendReply(AEDesc const*, AEDesc*) + 37
7   com.apple.AE                    0x00007fff93a5a869 aeProcessAppleEvent + 318
8   com.apple.HIToolbox             0x00007fff8d0c18e9 AEProcessAppleEvent + 100
9   com.apple.AppKit                0x00007fff8e95c916 _DPSNextEvent + 1456
10  com.apple.AppKit                0x00007fff8e95bed2 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
11  com.apple.AppKit                0x00007fff8e953283 -[NSApplication run] + 517
12  Test                            0x00000001070e1d68 main + 152 (Test.mm:31)
13  libdyld.dylib                   0x00007fff8e10c7e1 start + 1

测试用例的代码是:

// Tested with `clang++ -fobjc-arc -g Test.mm -framework Cocoa -o Test && ./Test`

#import <Cocoa/Cocoa.h>

@interface MyApplication : NSApplication
@end
@implementation MyApplication
- (void) applicationDidFinishLaunching: (NSNotification *) note
{
    NSWindow * window = [[NSWindow alloc] initWithContentRect: NSMakeRect(100, 100, 100, 100)
                        styleMask: NSTitledWindowMask backing: NSBackingStoreBuffered defer: YES];

    [window close];

    [super stop: self];
}
@end

int main()
{
    @autoreleasepool
    {
        const ProcessSerialNumber psn = { 0, kCurrentProcess };
        TransformProcessType(&psn, kProcessTransformToForegroundApplication);
        SetFrontProcess(&psn);

        [MyApplication sharedApplication];
        [NSApp setDelegate: NSApp];

        [NSApp run];
    }

    return 0;
}

推荐答案

使用Instruments的Zombies配置文件显示,通过调用close:将NSWindow对象放入自动释放池中.一旦applicationDidFinishLaunching:完成并销毁了NSWindow实例,ARC就会正确地以零的引用计数结束.但是,自动释放池仍然知道现在已终止的NSWindow实例,然后尝试在关闭时释放它,从而导致崩溃.

Using Instruments' Zombies profile showed that the NSWindow object gets put into the autorelease pool by the call to close:. ARC then correctly ends up with a reference count of zero once applicationDidFinishLaunching: completes and destroys the NSWindow instance. However, the autorelease pool still knows about the now-defunct NSWindow instance and then tries to release it on shutdown, causing the crash.

在ARC下管理自动释放对象似乎是个坏主意,除非自动释放池将对其对象的弱引用归零,这似乎在这里没有做.

Autoreleasing objects being managed under ARC seems like a bad idea unless the autorelease pool holds zeroing weak references to its objects, which it doesn't seem to be doing here.

通过添加[window setReleasedWhenClosed: NO];告诉窗口在关闭时不要自动释放,可以防止此问题.

The problem can be prevented by telling the window not to autorelease on close by adding [window setReleasedWhenClosed: NO];.

这篇关于为什么此简单的NSWindow创建代码在ARC下关闭时触发自动释放池崩溃?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆