0

XMLベースでプロトコル定義を構築するためにDelphi 7 XMLDocユニットを使用しています。つまり、プロトコルはXMLファイルで定義されており、一部のオブジェクトはこのXMLから情報を取得して、TCP / IPで配信されるISO8583メッセージを分解および構築します。IXMLDocumentIXMLNodeインターフェースを広く利用しています。すべて問題なく、終了時点で (FASTMM を使用して) メモリ リークはありません。しかし、実行中、ソフトウェアはゆっくりとメモリを消費します。TXMLDocumentXMLアクセスに使用しているオブジェクト(派生元)を解放すると、メモリが何らかの形で解放されます。IXMLDocument私が分析したところ、IXMLNodeインターフェイスを使用しなければメモリの問題はないことがわかりましたが、もちろん使用する必要があります。

TXMLTreeから派生したオブジェクト ( ) がありますTXMLDocmument

TXMLTree = class(TXMLDocument, IXMLDocument)
...
end;

別のオブジェクト ( TDPR) があり、そのコンストラクターでインターフェイス ( ) とドキュメントの開始点へのインターフェイス ( ) を作成TXMLTreeして取得します。fIDocumentfIDocStart

TDPR = class(TObject)
...
  fIDocument:IXMLDocument;
  fIDocStart:IXMLNode;
...
end;

constructor TDPR.Create(aFilename: string);
begin
  inherited; 
...
  fTree := TXMLTree.Create(aFilename);
  fTree.GetInterface(IXMLDocument, fIDocument);

  fIDocStart := fIDocument.DocumentElement;
...
end;

通常、XML ドキュメントに到達するための出発点としてfIDocumentandを使用しfIDocStart、次のようなコードを記述します。

node := fIDocument.DocumentElement.ChildNodes[aName].ChildNodes.FindNode(aFieldName);

また

node := fIDocStart.ChildNodes[aName].ChildNodes.FindNode(aFieldName);

そのような行は 1 行だけでゆっくりとメモリ使用量を増やすのに十分ですがfor、たとえば 1000 万のループでそれを実行すると、それ以上の効果はありません。

それではFoo、ドキュメントの開始点を取得する手順を見てみましょう。

procedure TDPR.Foo;
var lNode:IXMLNode;
begin
  lNode := IDocument.DocumentElement;
end;

このプロシージャを呼び出すと、メモリ使用量が少し増加しますが、定期的に呼び出すと、メモリが不足するのは時間の問題です。
ただしfIDocStart、必要なインターフェイスを既に格納している whichを使用するとDocumentElement、何度も呼び出す必要がなくなり、メモリの問題は発生しません。

procedure TDPR.Foo;
var lNode:IXMLNode;
begin
  lNode := fIDocStart;
end;

そのため、インターフェイス オブジェクト (など) を取得して返すすべての呼び出しでは、IXMLDocument IXMLNode IXMLNodeListメモリが割り当てられ、参照オブジェクトが適切に解放されている間はメモリが解放されないようです。同じノードを要求しても。もちろん、メモリを使い果たすのを避けるためだけに、考えられるすべてのノードを保存することはできません。

のデストラクタでは、対応するインターフェイスを に設定してTDPR解放し、終了時にメモリ リークは検出されません。参照カウンターは問題ないようです。TXMLTreenil

destructor TDPR.Destroy;
begin
...
  fIDocStart := nil;
  fIDocument := nil;

...
  inherited; 
end;

XMLまた、大きなファイルとは関係ありません。問題は次のXMLように同じです。

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl"?>
<Base24-POS>
   <Instructions>
      <Parameters Receive="1"/>
   </Instructions>
</Base24-POS>

私はそれが不明瞭であることを知っており、誰かがすでに同じ問題に遭遇し、解決策を見つけた可能性があることを願っています. (ところで、私はWindowsXPでまったく同じコードを問題なく使用したことを覚えています。現在はWindows7です)

4

1 に答える 1

0

この問題は、COM オブジェクト (XMLDocument は COM) へのマルチスレッド アクセスに何らかの形で関連していることがわかりました。やシングル スレッドTXMLDocumentなどのインターフェイスを介して作成および操作する場合、メモリの「リーク」はありませんでした。しかし、別のスレッドを使用しても問題を解決できませんでした。パラメータで CoInitializeEx を使用しました。すべてのスレッドは、インターフェイスを取得するときにメモリを割り当てて解放しないようです。すべてのスレッドは、少なくとも特定のインターフェイスに対して一度だけ割り当てるため、1 つのスレッドが目に見えるメモリ リークを引き起こすことはありません。しかし、動的に作成されたスレッドはすべてそのメモリを解放できず、最終的にプロセス メモリを消費します。今まで解決策が見つからなかったので、定期的にメモリをクリーニングすることを検討しましたIXMLDocumentIXMLNodeCOINIT_MULTITHREADEDSetProcessWorkingSet(ProcessHandle, -1, -1)そして、その対症療法は、より良い解決策に到達するまで問題を解決しました. また、この問題専用のマルチスレッド方式で Delphi7 COM インターフェイスを使用する場合のメモリ消費という新しい質問も開きました。

于 2013-10-28T18:30:03.717 に答える