0

我正在使用 Delphi 7 XMLDoc 单元在 XML 基础上构建协议定义,即协议在 XML 文件中定义,并且一些对象从该 XML 中获取信息,用于分解和构建在 TCP/IP 上传递的 ISO8583 消息。我广泛使用IXMLDocumentIXMLNode接口。一切都很好,在终止点没有内存泄漏(使用 FASTMM)。但是在运行过程中,软件会慢慢消耗内存。释放对象时,内存以某种方式释放 - 派生自TXMLDocument- 我用于 XML 访问。我分析发现如果我不使用IXMLDocumentIXMLNode接口没有内存问题,但我当然必须这样做。

我有一个对象 ( TXMLTree) 来自TXMLDocmument

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

我有TDPR另一个对象TXMLTreefIDocumentfIDocStart

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;

通常我使用fIDocumentandfIDocStart作为到达 XML 文档的起点,编写如下代码:

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

或者

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

只有这样一行就足以慢慢增加内存使用量,但如果我在for例如一千万的循环中执行它,则不会产生更多效果,因为 - 我猜 - 只有一个引用被使用并在循环中一直释放。

现在让我们有一个Foo获取文档起点的过程:

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

如果我调用此过程,它会稍微增加内存使用量,但会定期调用它,内存耗尽只是时间问题。
但是:如果我使用fIDocStartwhich 已经存储了所需的接口 - 所以不需要DocumentElement一次又一次地调用 - 没有内存问题。

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

因此,似乎每个获取和返回接口对象(IXMLDocument IXMLNode IXMLNodeList等等)的调用都会分配一些内存,并且在正确释放引用对象时不会释放它。即使我们要求同一个节点。当然,我不能存储所有可能的节点只是为了避免用完内存。

TDPR的析构函数中,我TXMLTree通过将对应的接口设置为释放,nil并且在终止时未检测到内存泄漏。参考计数器似乎没问题。

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当通过接口(例如在单个线程上)创建和操作它时IXMLDocument,没有内存“泄漏”。IXMLNode但是使用不同的线程我无法消除这个问题。我使用带有参数的 CoInitializeEx COINIT_MULTITHREADED。似乎每个线程在获取接口时都会分配一些内存并且不会释放它,并且每个线程都会分配一次 - 至少对于某个接口,因此一个线程不会导致可见的内存泄漏。但是动态创建的线程都无法释放该内存并最终消耗掉进程内存。直到现在我还没有找到解决方案,所以我考虑定期清理内存SetProcessWorkingSet(ProcessHandle, -1, -1)对症治疗解决了问题,直到找到更好的解决方案。我还打开了一个新问题Memory consumption when using Delphi7 COM interfaces in a multithreaded way专门解决这个问题。

于 2013-10-28T18:30:03.717 回答