适用于iPhone的NSXMLParser内存分配效率

时间:2010-01-22 15:35:54

标签: iphone cocoa memory-management nsxmlparser

我最近一直在玩iPhone应用程序的代码来解析XML。坚持Cocoa,我决定使用NSXMLParser类。该应用程序将负责解析10,000多个“计算机”,所有这些计算机都包含6个其他信息串。对于我的测试,我已经验证了XML的大小约为900k-1MB。

我的数据模型是通过唯一标识符将每台计算机保存在NSDictionary中。每台计算机也由NSDictionary代表信息。所以在一天结束的时候,我最终得到了一个包含10k其他NSDictionaries的NSDictionary。

我遇到的问题不是泄漏内存或高效的数据结构存储。当我的解析器完成后,分配的对象总量只会增加大约1MB。问题是当NSXMLParser运行时,我的对象分配高达13MB。我能理解2(一个用于我正在创建的对象,一个用于原始NSData)加上一个小工作空间,但13似乎有点高。我无法想象NSXMLParser效率低下。想法?

...代码

开始解析的代码......

NSXMLParser *parser = [[NSXMLParser alloc] initWithData: data];
[parser setDelegate:dictParser];
[parser parse];
output = [[dictParser returnDictionary] retain];        
[parser release];
[dictParser release];

解析器的委托代码......

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {

    if(mutableString)
    {
        [mutableString release];
        mutableString = nil;

    }

    mutableString = [[NSMutableString alloc] init];     

}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { 
    if(self.mutableString)
    {

        [self.mutableString appendString:string];

    }
}

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

    if([elementName isEqualToString:@"size"]){
        //The initial key, tells me how many computers
        returnDictionary = [[NSMutableDictionary alloc] initWithCapacity:[mutableString intValue]];
}

    if([elementName isEqualToString:hashBy]){
    //The unique identifier
        if(mutableDictionary){
            [mutableDictionary release];
            mutableDictionary = nil;
    }       

        mutableDictionary = [[NSMutableDictionary alloc] initWithCapacity:6];

        [returnDictionary setObject:[NSDictionary dictionaryWithDictionary:mutableDictionary] forKey:[NSMutableString stringWithString:mutableString]];
}

    if([fields containsObject:elementName]){
        //Any of the elements from a single computer that I am looking for
        [mutableDictionary setObject:mutableString forKey:elementName];
}
}

正确初始化和发布的所有内容。再次,我没有得到错误或泄漏。效率低下。

感谢您的任何想法!

7 个答案:

答案 0 :(得分:6)

NSXMLParser是一个记忆猪:

  1. 它不是真正的流解析器: initWithURL:将全部下载 xml在处理之前。为了记忆 使用这是不好的,因为它必须 为完整的xml分配内存 直到最后才能收回 结束解析。为了表现它 也不好,因为你不能交错 下载的IO密集部分 和CPU密集的解析部分。
  2. 它不会释放记忆。它似乎 创建的字符串/字典 在解析过程中保持不变 直到解析结束。我试过了 通过创造性地使用它来改进它 NSAutoreleasePool但没有任何 成功。
  3. 替代方案是libxml和AQXMLParser,它是围绕libxml的NSXMLParser兼容包装,或ObjectiveXML

    有关详细信息,请参阅my blog article

答案 1 :(得分:3)

不能说出你的代码的具体内容,但看看Apple的XMLPerformance样本 - 它比较了NSXMLParser和libxml的性能 - 结果肯定是后者的优势。在我的一个项目中,从NSXMLParser切换到libxml提高了性能,所以我建议使用它。

答案 2 :(得分:0)

我使用NSXMLParser解析大约500条记录的XML文件,大约700K左右。我发现这是iPhone 3G内存限制的上端。内存扩展到远远超过XML文件的大小,有时达到15MB。问题是我将记录存储在一个数组中,因此两者同时存在于内存中。解析完成的内存再次下降,但如果它达到15或20MB,应用程序将崩溃。 libxml应该具有更高的内存效率。

您也可以尝试使用Core Data而不是数组存储创建的对象。核心数据通过在不需要时释放对象来更好地处理内存。

使用我的应用程序,我通过优化其他部分减少了内存开销,因此使用的总内存从未达到上限。

答案 3 :(得分:0)

如果您想知道内存的去向,请使用ObjectAlloc模板运行Instruments下的代码,并按总大小对类列表进行排序。一旦整体内存使用量变大,您将看到一个类或几个类作为内存的最大占用者。

然后,深入研究其中一个类并检查它的实例以查看创建它们的内容。

然后,您将从证据中知道,问题所在。

答案 4 :(得分:0)

刚切换到 libxml

有点头疼,但弗拉基米尔发布的链接是一个巨大的帮助。

现在900k - 1mb文件的膨胀只有2-3mb左右。另外,因为它是一个流解析器,它几乎在NSURLRequest返回后立即完成。

最终答案 - libxml。

感谢你们的帮助!

答案 5 :(得分:0)

如果您正在寻找NSXMLParser的替代品,它可以通过http处理大型XML文档的流式传输,您可能会对我的Expat Objective C Wrapper感兴趣。

答案 6 :(得分:0)

我之前使用过AQXMLParser,它的内存效率肯定比NSXMLParser高得多。