6

私は最近、XML を解析する iPhone アプリのコードをいじっています。Cocoa にこだわり、NSXMLParser クラスを使用することにしました。このアプリは、10,000 台以上の「コンピューター」の解析を担当し、そのすべてに 6 つの他の文字列の情報が含まれています。私のテストでは、XML のサイズが約 900k-1MB であることを確認しました。

私のデータ モデルは、一意の識別子でハッシュされた NSDictionary に各コンピューターを保持することです。各コンピューターは、情報を含む NSDictionary によっても表されます。そのため、最終的には、10k の他の NSDictionary を含む NSDictionary になります。

私が直面している問題は、メモリリークや効率的なデータ構造ストレージに関するものではありません。私のパーサーが完了すると、割り当てられたオブジェクトの合計量は約 1MB しか増加しません。問題は、NSXMLParser の実行中に、オブジェクトの割り当てが 13MB も跳ね上がることです。2 (作成中のオブジェクト用と生の NSData 用に 1 つ) に加えて、少し余裕があることは理解できましたが、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];
}
}

すべてが正しく初期化され、リリースされました。繰り返しますが、エラーやリークは発生していません。ただ効率が悪い。

ご意見ありがとうございます。

4

7 に答える 7

6

NSXMLParser はメモリを大量に消費します:

  1. これは実際のストリーミング パーサーではありません: initWithURL: 処理する前に完全な xml をダウンロードします。メモリの使用に関しては、解析が終了するまで再利用できない完全な xml にメモリを割り当てる必要があるため、これは良くありません。ダウンロードの IO 集中型部分と解析の CPU 集中型部分をインターリーブできないため、パフォーマンスも悪くなります。
  2. メモリを解放しません。解析中に作成された文字列/辞書は、解析が終了するまで保持されているようです。私はそれを創造的に使用して改善しようとしまし NSAutoreleasePoolたが、成功しませんでした。

代替手段は、 libxml と、 libxmlの NSXMLParser 互換ラッパーである AQXMLParser 、またはObjectiveXMLです。

詳細については、私のブログ記事を参照してください。

于 2010-01-22T21:23:01.517 に答える
3

コードについて具体的なことは言えませんが、Apple のXMLPerformanceサンプルを見てください - NSXMLParser と libxml のパフォーマンスを比較しています - 結果は間違いなく後者に有利です。私のプロジェクトの 1 つで、NSXMLParser から libxml に切り替えるとパフォーマンスが大幅に向上したので、それを使用することをお勧めします。

于 2010-01-22T15:51:41.163 に答える
0

以前にAQXMLParserを使用したことがありますが、NSXMLParserよりもメモリ効率がはるかに高いことは間違いありません。

于 2010-06-14T00:11:19.797 に答える
0

メモリの行き先を知りたい場合は、ObjectAllocテンプレートを使用してInstrumentsでコードを実行し、クラスリストを合計サイズで並べ替えます。全体的なメモリ使用量が膨大になると、1つのクラスまたはいくつかのクラスがメモリの最大の占有者として表示されます。

次に、これらのクラスの1つにドリルダウンし、そのインスタンスを調べて、何がそれらを作成したかを確認します。

そうすれば、証拠から、問題がどこにあるのかがわかります。

于 2010-01-22T21:37:06.570 に答える
0

NSXMLParserを使用して、700K程度で約500レコードのXMLファイルを解析しました。これはiPhone3Gのメモリ制限の上限にあることがわかりました。メモリはXMLファイルのサイズをはるかに超えて拡張され、15MBに達することもありました。問題は、レコードを配列に格納していたため、両方が同時にメモリに格納されていたことです。解析が終了すると、メモリは再びダウンしましたが、15MBまたは20MBに達すると、アプリがクラッシュします。libxmlは、はるかにメモリ効率が高いと思われます。

作成したオブジェクトを配列ではなくCoreDataで保存することもできます。Core Dataは、オブジェクトが不要なときにオブジェクトの割り当てを解除することで、メモリをより多く処理します。

私のアプリでは、他の部分を最適化することでメモリオーバーヘッドを削減し、使用されるメモリの合計が上限に達することはありませんでした。

于 2010-01-22T16:39:43.270 に答える
0

libxmlに切り替えただけです。

少し頭痛の種ですが、ウラジミールが投稿したリンクは大きな助けになりました。

現在、900k - 1mb のファイルの肥大化はわずか 2 - 3mb 程度です。さらに、これはストリーミング パーサーであるため、返された直後に実行されNSURLRequestます。

最終的な答え - libxml.

助けてくれてありがとう!

于 2010-01-25T03:42:37.620 に答える
0

http を介した大きな XML ドキュメントのストリーミングを処理できる NSXMLParser の代替を探している場合は、私のExpat Objective C Wrapperに興味があるかもしれません。

于 2010-05-24T21:05:46.293 に答える