Objective c 清理应用程序全球资源的最佳场所?

Objective c 清理应用程序全球资源的最佳场所?,objective-c,macos,nsdocument,nsapplication-delegate,Objective C,Macos,Nsdocument,Nsapplication Delegate,停止按确定在您看到以下问题中的单词重新计数之前,请跳到底部的编辑,我已声明我已停止使用它 在调用NSApplicationMain()之前,我使用的Cocoa应用程序创建了许多全局资源,我正在main()中加载这些资源。由于NSApplicationMain()没有返回,我使用atexit()连接了这些资源的清理,如下所示: atexit(cleanup); if (![CocoaUtil initCocoaUtil] || ![PreferenceController initPre

停止按确定在您看到以下问题中的单词
重新计数
之前,请跳到底部的编辑,我已声明我已停止使用它

在调用
NSApplicationMain()
之前,我使用的Cocoa应用程序创建了许多全局资源,我正在
main()
中加载这些资源。由于
NSApplicationMain()
没有返回,我使用
atexit()
连接了这些资源的清理,如下所示:

atexit(cleanup);

if (![CocoaUtil initCocoaUtil] ||
    ![PreferenceController initPreferenceController] ||
    ![ResourceManager initResourceManager])
{
    criticalAlertPanel(@"Failed to initialize application",
                       @"Failed to initialize application");
    return 4;
}

retval = NSApplicationMain(argc, (const char **)argv);
但是,
cleanup()
在我的
NSDocument
子类中的任何视图都是
dealloc
'd之前被调用(我没有日志消息来显示这一点),因此全局资源中对象的引用计数有时是
>1
。我过于谨慎,试图通过使用此方法释放我的全局资源来预防内存泄漏:

+ (void)fullRelease:(id)obj
             format:(NSString *)format, ...
{
    if (obj == nil)
        return;

    NSUInteger retainCount = [obj retainCount];
    if (retainCount > 1)
    {
        va_list va;
        va_start(va, format);
        NSString *objDesc = [[NSString alloc] initWithFormat:format arguments:va];
        logwrn(@"%@ has a reference count of %lu", objDesc, retainCount);
        [objDesc release];
    }

    while (retainCount > 0)
    {
        [obj release];
        retainCount--;
    }
}
我的日志显示以下内容:

12:15:04.954 INF -[AppController applicationDidFinishLaunching:] Application launched
12:15:06.702 INF -[AppController applicationShouldTerminate:] Application terminating
12:15:06.703 INF -[AppController applicationWillTerminate:] Application terminating
12:15:06.705 DBG cleanup Cleaning-up
12:15:06.705 INF +[ResourceManager finiResourceManager] Cleaning up
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[2] has a reference count of 2
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[3] has a reference count of 2
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[4] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[5] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[6] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[7] has a reference count of 2
12:15:06.711 WRN +[CocoaUtil fullRelease:format:] _images[8] has a reference count of 2
12:15:06.711 WRN +[CocoaUtil fullRelease:format:] _images[9] has a reference count of 2
12:15:06.721 DBG +[PreferenceController finiPreferenceController] Cleaning up
12:15:06.721 DBG +[CocoaUtil finiCocoaUtil] Cleaning up
我的问题(最后!)是:

是否有办法确保在所有
NSDocument
实例被销毁后清理我的全局资源,并停止这些误报

EDIT:我已取消了
fullRelease
调用,只是对我的资源和仪器执行了正常的
release
,没有检测到任何内存泄漏,因此一切正常,但我很好奇为什么
NSDocument
对象在
atexit()之前似乎没有被释放
被调用。

不要发布你不拥有的东西

每个人都属于别人。仅向对象发送
release
,以平衡对
new
alloc
copy
retain
(NARC)的调用。这种行为将不可避免地导致生产代码崩溃

看起来您希望确保对象被解除分配,而不是简单地处理。如果您拥有该对象,请将其释放一次;对它的其他引用属于其他对象。您的代码中可能确实存在内存泄漏(我们不能仅从这个代码示例中判断),但这些泄漏通常可以通过静态分析器、仪器和少量润滑脂找到

更重要的是:当进程退出时,操作系统将为您释放所有内存。这不是C标准的一部分,但它只是OS X和iOS的操作方式,这是支持Objective-C的其他平台上的预期行为。因此,当进程退出时,您不必做任何特殊的清理工作,可能只需将文件写入磁盘或类似文件。事实上,许多Cocoa应用程序都懒得释放其应用程序代理拥有的任何东西,因为让操作系统转储内存比在数千个对象上调用
-release
更快

不要调用
-重新计数


这是谎言。简单明了。它包括Cocoa使用的临时引用,最重要的是,您不应该试图干扰这些引用<代码>-重新计数是有毒符号。

禁用突然终止,不使用全局值,只使用常规引用计数规则。在某些情况下,您需要中断强循环引用或手动清除对象的实例变量。最后,在main返回之前暂停/中断,并运行
heap
,查看在这个阶段什么是真正活跃的(泄漏),可能会更有帮助

我过于谨慎,试图通过使用此方法释放全局资源来预防内存泄漏

您不应该像这样清除-您更清楚:)


但是,查找和销毁您控制的所有引用/对象/分配实际上是一种非常好的做法,以确保您的程序能够正常工作、可重用,并在应用程序发生变化时监控回归的良好指标。

正如所有其他人所说:只发布您拥有的。你的应用程序现在可能不会崩溃,但你只是运气好而已。当你这样做的时候,或者在两个小时内,或者其他任何时候,它可能会在另一台Mac上崩溃

如果您拥有某个对象所持有的稀缺资源,而该资源确实需要从中注销(例如,到另一台服务器的网络会话,如果未正确发送注销消息,将导致服务器等待您,保留一些内部状态以供返回),您应该将其构建到对象中,而不是在释放对象时进行构建

例如,Mac OS X在您的应用程序退出之前发送通知,NSApplication将终止。让您的对象注册它,当它得到它时,让它向服务器发送再见(记住它已经这样做了)。这样,当您的应用程序退出时,例如,应用程序委托仍保留该对象,您仍然可以确定会发生注销

但是您可能还应该检查您是否已经在-dealloc中签署了。有一天你可能会添加对多个服务器的支持,然后当你发布一个服务器时,你希望它发送一个再见,即使你的应用程序不会退出。但只有在你还没有完成的情况下才可以签字

当您在退出之前内存中有一些数据需要写入时,情况也是如此(例如,NSUserDefaults就是这样做的,以确保快速访问首选项,但在退出之前它仍然会写入磁盘)

但这样的案例真的很少见。通常,NSDocument会在需要时调用您写入磁盘,通常服务器会在连接断开时通知您并自行清理。所以你真的不应该发布不属于你的东西。你只会导致一些用户在退出时崩溃。它给人的印象非常糟糕,可能会导致你的应用程序在有机会保存某些数据之前实际失败,从而使事情变得更糟。

一些注意事项: