为什么静态NSString泄漏?

时间:2011-06-25 04:05:48

标签: iphone objective-c ios memory-leaks

我有以下代码来检索iOS应用程序上的文件路径:

static const NSString * fullPathFromRelativePath(NSString *relPath)
{
    // do not convert a path starting with '/'
    if(([relPath length] > 0) && ([relPath characterAtIndex:0] == '/'))
        return relPath;

    NSMutableArray *imagePathComponents = [NSMutableArray arrayWithArray:[relPath pathComponents]];

    NSString *file = [imagePathComponents lastObject];    
    [imagePathComponents removeLastObject];

    NSString *imageDirectory = [NSString pathWithComponents:imagePathComponents];

    NSString *fullpath = [[NSBundle mainBundle] pathForResource:file
                                                         ofType:NULL
                                                    inDirectory:imageDirectory];
    if (!fullpath)
        fullpath = relPath;

    return fullpath;    
}

static const char * fullCPathFromRelativePath(const char *cPath)
{
    NSString *relPath = [NSString stringWithCString:cPath encoding:NSUTF8StringEncoding];
    const  NSString *path = fullPathFromRelativePath(relPath);
    const char *c_path = [path UTF8String];
    return c_path;
}

static const char * relativeCPathForFile(const char *fileName)
{        
    NSString *relPath = [NSString stringWithCString:fileName encoding:NSUTF8StringEncoding];        
    const NSString *path = fullPathFromRelativePath(relPath);
    const char *c_path = [[path stringByDeletingLastPathComponent] UTF8String];    
    return c_path;
}

我在调试控制台中收到了很多这样的消息:

objc[4501]: Object 0x6e17060 of class __NSCFString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
objc[4501]: Object 0x6e12470 of class NSPathStore2 autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
objc[4501]: Object 0x6e12580 of class __NSCFData autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug

代码有什么问题? (我甚至使用iOS 5进行“自动”保留/释放等)

干杯。

4 个答案:

答案 0 :(得分:11)

当您在其堆栈中没有任何发布池的线程上自动释放对象时,会显示此消息。默认情况下,主线程上始终存在自动释放池。它是在UIApplicationMain()函数中创建和管理的,该函数通常由应用程序的main()函数调用。但是,您创建的其他线程(使用performSelectorInBackground:NSThread)没有自动释放池,除非您专门放置一个,因此该后台线程上的任何自动释放的对象都没有池以便稍后释放它们,而且会泄漏。

如果您正在向后台线程踢一些东西,那么您应该做的第一件事就是创建一个自动释放池。在ARC下,使用新的@autoreleasepool构造来执行此操作。

答案 1 :(得分:1)

您是否尝试在非ARC应用程序中运行相同的代码?通过这样做,您可以确认它是ARC问题还是框架中的真正错误。 ARC仍然不成熟,苹果已多次表示尚未完成,并且肯定存在漏洞。

如果您担心正在创建的明显自动释放对象的数量,请在相关代码周围使用@autoreleasepool {...}构造。它比NSAutoreleasePool要大more efficient,无论如何都无法在ARC代码中创建。

答案 2 :(得分:0)

我认为这不是真正的泄漏。 Apple已经讨论了几次,在模拟器上它是模拟器库如何处理NSAutoReleasePool的一个已知的伪bug,但不足以保证修复,因为你的mac有比设备多得多的内存。在WWDC他们提到有一些地方NSZombie没有正确处理autorelease,但我不记得在哪个会话。除非你注意到Leaks中的那些对象,你不应该担心它。如果您确实注意到使用乐器泄漏,请提交bugreport

请勿在您的方法周围创建自动释放池,因为它看起来可能正在泄漏。在ARC上无论如何都无法工作,除非你修改了应用程序的main()函数,否则你有一个自动释放池包装一切。在调用该方法后,创建一个额外的自动释放池而不分析数据表明您有严重的内存压力,这实际上会使您的应用程序性能下降。

答案 3 :(得分:0)

如果您已在main.m文件中删除了NSAutoreleasePool调用,或者此代码正在一个单独的线程中执行,则会发生这种情况。 因为您不能在ARC中使用NSAutoreleasePool,所以必须将线程代码放在@autoreleasepool块中