我最近一直在玩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];
}
}
正确初始化和发布的所有内容。再次,我没有得到错误或泄漏。效率低下。
感谢您的任何想法!
答案 0 :(得分:6)
NSXMLParser是一个记忆猪:
initWithURL
:将全部下载
xml在处理之前。为了记忆
使用这是不好的,因为它必须
为完整的xml分配内存
直到最后才能收回
结束解析。为了表现它
也不好,因为你不能交错
下载的IO密集部分
和CPU密集的解析部分。NSAutoreleasePool
但没有任何
成功。替代方案是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高得多。