問題
通常、XML の使用について言及するとき、最も問題になるのは XML の冗長性と XML の解析速度です。この問題は、大きな XML ファイルを処理する必要がある場合に特に深刻になります。ここで言及するのは、XML の処理速度を最適化する方法に関するトピックです。
XML ファイルの処理を選択する場合、通常 2 つのオプションがあります:
DOM。これは、XML の構造情報をツリー状に構築し、インターフェースとメソッドをトラバースする方法を提供します。 。
SAX は低レベルのパーサーであり、要素ごとに前方読み取り専用処理を実行しますが、構造情報は含まれません。
上記のオプションにはそれぞれ長所と短所がありますが、どちらも特に優れた解決策というわけではありません。長所と短所は次のとおりです:
DOM
利点: すべての XML 構造情報がメモリ内に存在するため、使いやすい。シンプルなトラバーサルと XPath のサポート。
短所: 解析速度が遅すぎ、メモリ使用量が高すぎ (元のファイルの 5 倍から 10 倍)、大きなファイルに使用するのはほぼ不可能です。
SAX
利点: 解析は高速で、メモリ使用量は XML のサイズに関係ありません (XML が大きくなってもメモリを増やすことなく実行できます)。
短所: 構造情報がないため、トラバースできず、XPath をサポートしていないため、使いやすさが劣ります。構造が必要な場合、少し読んで少し構築するだけで済み、メンテナンス性が非常に悪いです。
基本的に DOM と SAX は両極端であることがわかりますが、どちらもほとんどの要件を十分に満たすことができず、別の処理方法を見つける必要があります。 XML の効率の問題は、XML 自体の問題ではなく、上で見た 2 つの方法が異なる効率のトレードオフを持っているのと同じように、XML を処理するパーサーの問題であることに注意してください。
考え方
私たちは DOM のようなメソッドを使用することを好みます。トラバースできるため、つまり XPath がサポートされ、使いやすさが大幅に向上しますが、DOM の効率は非常に低いです。すでにご存知のとおり、効率の問題は処理メカニズムにあります。では、DOM のどのような側面がその効率に影響を与えるのでしょうか?以下で包括的な分析を行ってみましょう:
仮想マシン (ホスト型、または類似のメカニズム) テクノロジーに基づいた今日のほとんどのプラットフォームでは、オブジェクトの作成と破棄は時間のかかる作業です (ここでは主にガベージ コレクションについて言及する価値があります)時間がかかりますが、DOM メカニズムで使用される多数のオブジェクトの作成と破棄は、間違いなくその効率に影響を与える理由の 1 つです (大量のガベージ コレクションが発生します)。
各オブジェクトには、そのメモリ アドレスを保存するために追加の 32 ビットが必要になります。DOM のように多数のオブジェクトがある場合、この追加コストは小さくありません。上記 2 つの問題を引き起こす主な効率の問題は、DOM と SAX の両方が抽出解析モードであるため、DOM と SAX の両方で大量のオブジェクトの作成 (破棄) が必要となり、効率の問題が発生することです。いわゆる抽出解析とは、XML を解析するときに、DOM または SAX が元のファイルの一部 (通常は文字列) を抽出し、それをメモリ内で解析して構築することを意味します (出力は当然 1 つまたはいくつかのオブジェクトです)。 DOM を例に挙げると、DOM は各要素、属性、処理命令、コメントなどをオブジェクトに解析し、それに構造を与えます。これはいわゆる抽出解析です。
抽出の問題によって引き起こされるもう 1 つの問題は、DOM では更新効率です (SAX は更新をサポートしていないため、これについてはまったく触れません)。変更が必要になるたびに、必要なのは、オブジェクト情報を再度 XML 文字列を返します。この解析は完全な解析であることに注意してください。つまり、元のファイルは使用されませんが、DOM モデルは完全に XML 文字列に直接再解析されます。つまり、DOM は Incremental Update (増分更新) をサポートしていません。
気づかれないかもしれないもう 1 つの「小さな」問題は、XML のエンコーディングです。どのような解析方法を使用する場合でも、XML のエンコーディング、つまり、読み取り時と書き込み時のデコードを処理できる必要があります。 DOM に関するもう 1 つの効率の問題は、大規模な XML に小さな変更を加えるだけの場合、最初にファイル全体をデコードしてから構造を構築する必要があることです。目に見えないが、それは別の出費である。
問題を要約すると、DOM の効率の問題は主に抽出解析モードにあります (SAX にも同じ問題があり、これが一連の効率のボトルネックを引き起こしています)。そうすれば、さらにXMLの処理効率が向上すると考えられる。 XML の使いやすさや処理効率が大幅に向上すれば、XML の適用範囲や適用モデルはさらに昇華され、これまで考えられなかった素晴らしいものが数多く生み出されるかもしれません。
VTD-XML の解析速度は、SAX (NULL コンテンツ ハンドラーを使用) の 1.5 倍から 2.0 倍です。 NULL コンテンツ ハンドラーを使用すると、SAX 解析に追加の処理ロジックが挿入されないことを意味します。これが SAX の最大速度です。
VTD-XML のメモリ使用量は、元の XML の 1.3 倍から 1.5 倍になります (1.0 倍の部分は元の XML、0.3 倍から 0.5 倍の部分は VTD-XML が占める部分です)。 DOM の使用法は、元の XML の 5x ~ 10x と同じです。たとえば、XML のサイズが 50MB の場合、VTD-XML が占有するメモリは 65MB ~ 75MB となり、DOM が占有するメモリは 250M ~ 500MB になります。 DOM を使用して、このデータに基づいて大きな XML ファイルを処理することは、ほぼ不可能なオプションです。
信じられないと思われるかもしれませんが、DOM よりも使いやすく、SAX よりも高速な XML パーサーを作成することは本当に可能でしょうか?結論を急がずに、VTD-XML の原則を見てみましょう。
基本原理
ほとんどの優れた製品と同様、VTD-XML の原理は複雑ではありませんが、非常に賢明です。非抽出の目的を達成するために、元の XML ファイルをデコードせずにそのままバイナリ モードでメモリに読み込み、このバイト配列上の各要素の位置を解析して、後続の走査操作を記録します。これらの保存されたレコードに対して実行され、XML コンテンツを抽出する必要がある場合は、レコード内の位置とその他の情報を使用して元のバイト配列がデコードされ、文字列が返されます。これはすべて単純に見えますが、この単純なプロセスには複数のパフォーマンスの詳細があり、いくつかの潜在的な機能が隠されています。まず、各パフォーマンスの詳細を説明します。
過剰なオブジェクトの作成を避けるために、VTD-XML は、ヒープが必要ないように、レコード タイプとして元の数値タイプを使用することにしました。 VTD-XML の記録メカニズムは VTD (Virtual Token Descriptor) と呼ばれ、VTD はトークン化段階でのパフォーマンスのボトルネックを解決します。これは実に賢明で思慮深いアプローチです。 VTDは、各要素の開始位置(オフセット)、長さ(length)、深さ(深さ)、トークンの種類(タイプ)などの情報を記録する64ビット長の数値型です。
VTD は固定長であることに注意してください (正式に 64 ビットを使用することが決定されました)。これは、長さが固定されているため、読み取り、クエリ、その他の操作の際に非常に効率的 (O(1)) です。 VTD を編成する配列の効率的な構造により、オブジェクトの大量使用によって引き起こされるパフォーマンスの問題が大幅に軽減されます。 VTD の超強力な点は (まったく誇張ではありません)、XML などのツリー状のデータ構造をバイト配列の操作に簡単に変換できることです。想像できるあらゆる操作を XML に適用できます。これは、読み込まれる XML がバイナリ (バイト配列) であるため、VTD には各要素の位置やその他のアクセス情報が記録されており、操作対象の VTD を見つけるには、オフセットや長さなどの情報を使用するだけで済みます。元のバイト配列を操作することも、VTD を直接操作することもできます。たとえば、大きな XML 内の要素を見つけて削除したい場合は、この要素の VTD を見つけて (走査方法については後で説明します)、この VTD を VTD 配列から削除して、次を使用するだけです。すべて VTD を別のバイト配列に書き込むだけです。削除された VTD は削除される要素の位置をマークするため、この要素は新しく書き込まれるバイト配列には表示されません。バイト配列は実際には のコピーです。これは、いわゆる増分更新であり、その効率は非常に高いです。
VTD-XML のトラバーサル方式に関しては、LC (Location Cache) を使用します。LC (Location Cache) は、VTD の深さを標準として構築されたツリー状のテーブル構造です。 LC のエントリも 64 ビット長の数値タイプで、最初の 32 ビットは VTD のインデックスを表し、最後の 32 ビットはこの VTD の最初の子のインデックスを表します。この情報を使用して、到達したい位置を計算できます。具体的な移動方法については、公式 Web サイトの記事を参照してください。この走査方法に基づく VTD-XML は DOM とは異なる操作インターフェイスを備えていることは理解できますが、この VTD-XML の走査方法は最小限のステップで必要な場所に移動できるため、走査パフォーマンスが非常に優れています。