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会在需要时调用您写入磁盘,通常服务器会在连接断开时通知您并自行清理。所以你真的不应该发布不属于你的东西。你只会导致一些用户在退出时崩溃。它给人的印象非常糟糕,可能会导致你的应用程序在有机会保存某些数据之前实际失败,从而使事情变得更糟。一些注意事项:
- 做