【问题标题】:Memory Leak with NSMutableString appendString内存泄漏与 NSMutableString appendString
【发布时间】:2011-01-04 10:26:08
【问题描述】:

我正在使用 XMLParser 来解析一些 XML 数据,它使用 NSMutableString *resultString 来存储标记字符。在每个 (- parser: didStarElement...) 方法中,我分配并初始化 resultString-ivar。

-  (void)parser: (NSXMLParser *)parser didStartElement: (NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qName attributes: (NSDictionary *)attributeDict { 
// Alot of if-statements to sort subtags
// /.../
    resultString = [[NSMutableString alloc] init];
    recordResults = YES;
}

字符串附加在 parser:foundCharacters 方法中。我在某处读到自动释放对象,例如 appendString 中的字符串可能会导致内存泄漏的图像。所以我添加了一个本地自动释放池以确保它立即被耗尽(虽然行为没有改变):

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if(recordResults) {
    [resultString appendString: string];
}
[pool drain];
}

在解析器中:didEndElement...我终于释放并清除了结果字符串:

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

   // Alot of if statements to handle differnt tags
   // each of which has the structure of the last else-statement
   // In other words, I am pretty sure I've covered every possible
   // case to prevent the resultString from
   // not getting released and niled out
    if(...) {
            ...
}
    else if(...) {
            ...
    }
else {
    if(resultString != nil) {
        [dataDict setObject: resultString forKey: elementName];
        [resultString release];
        resultString = nil;
    }
}

Instruments Leak-tool 将 parser:foundCharacter-method 标记为内存泄漏源,所以我想知道这是否是由 appendString 引起的。或者,如果您可以在此代码中找到一些错误的地方。 这是一个相当需要内存的应用程序,在 iPhone 上解析很多,有时是中等大小的 XML 文件,所以我的问题是如何找到解决方法,如果 NSMutableString appendString 在这种情况下不合适......

提前致谢!

【问题讨论】:

    标签: iphone memory string append memory-leaks


    【解决方案1】:

    如果缺少结束标记,则会发生内存泄漏。最好在 parserDidStartDocument: 中进行任何分配,并在 parserDidEndDocument: 中进行释放,因为它们保证是成对的。而不是在 didStartElement 中分配 resultString,你只是在那里截断它。

    【讨论】:

    • 我不确定是否会在解析错误时调用 parserDidEndDocument,但这应该很容易测试。
    • 好点!应该对性能进行一些改进,对吧,因为我不必为每个标签分配和初始化 NSMutableString?通过截断,您建议只设置 [resultString setString:@""]?
    • 我试过你的这个解决方案。它似乎已经解决了这个问题。非常感谢!我很幸运能够使用带有结束标记的 XML。但如果不是,我想我可以实现 parser:parseErrorOccured 或其他东西来处理这些......
    • 不幸的是没有解决,但我认为你让我走上了正确的道路。当我解决这个问题或需要更多反馈时会发表评论。还是谢谢...
    • 您的建议的问题是,通过截断 resultString 而不重新指向它,我还更改了添加它的 Dictionary 中的值。除了释放它并消除它之外,我似乎没有找到任何补救措施,就像我的第一个代码示例一样......
    【解决方案2】:

    我认为您无法知道appendString 是否正在使用autorelease,因为该方法更改了它的对象而不是返回一个新对象。换句话说,因为它在改变自己,所以你不负责它的内存管理。您也不拥有string,因此您不必释放或自动释放它。

    看看这个:http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH

    这可能会澄清一些事情,但自动释放的关键是由 alloc/init 以外的东西返回的“新”对象是自动释放的。在这种情况下,appendString 不会返回新对象,字符串可以简单地保留,传递给解析器回调,然后由调用者稍后释放,所以谁知道它是否是自动释放的。

    你必须自动释放某些东西的时候是当你有一个使用 alloc/new/copy 的函数/方法,然后返回对象而函数本身无法在将来释放它。

    【讨论】:

    • 我同意我也可以省略自动释放池。我在stackoverflow上得到了一个提示,虽然我不明白为什么它应该有帮助,但我尝试了它。我试图在第一篇文章中提到这一点,但显然不够清楚。
    【解决方案3】:

    自动释放池没有做任何事情,因为您没有自动释放任何对象 - 您将可变字符串分配到一个位置,然后将其释放到另一个位置。 "appendString" 对 MutableString 的保留计数没有任何作用。

    至于泄漏,这里是交易 - Leaks 告诉您内存泄漏在哪里分配。所以这意味着在分配内存的部分一切正常 - 不正常的是,在其他地方保留在该方法中的内存应该被释放,但它没有。

    因此,在稍后的某个时间点,您似乎从放置它的 dataDict 中取出 resultString,保留它而不释放它(在我看来,您在解析时释放它 OK,所以这不是罪魁祸首)。要验证这一点,请将字符串的插入更改为::

     [dataDict setObject:[[resultString copy] autorelease] forKey: elementName];
    

    并且泄漏应该告诉您泄漏存在。为了帮助追踪泄漏,每当您从该 dataDict 中提取字符串时,您都可以[复制]它,然后您将更接近泄漏字符串的确切代码。

    基本上泄漏就像打开一本神秘的书,有人死了。由你决定谁是凶手 - 或者在泄密的情况下,谁应该杀人但没有解决。

    【讨论】:

    • 是的,你是对的。然而。它也没有真正的伤害,而且我仍然有泄漏,所以我仍然很困惑。
    • 我在我的回复中添加了一条关于泄漏真正告诉你的注释,抱歉我没有在那天晚上详细说明,但当时我太着急了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 2011-10-16
    • 2019-08-08
    相关资源
    最近更新 更多