我正在使用 Delphi 7 XMLDoc 单元在 XML 基础上构建协议定义,即协议在 XML 文件中定义,并且一些对象从该 XML 中获取信息,用于分解和构建在 TCP/IP 上传递的 ISO8583 消息。我广泛使用IXMLDocument
和IXMLNode
接口。一切都很好,在终止点没有内存泄漏(使用 FASTMM)。但是在运行过程中,软件会慢慢消耗内存。释放对象时,内存以某种方式释放 - 派生自TXMLDocument
- 我用于 XML 访问。我分析发现如果我不使用IXMLDocument
和IXMLNode
接口没有内存问题,但我当然必须这样做。
我有一个对象 ( TXMLTree
) 来自TXMLDocmument
:
TXMLTree = class(TXMLDocument, IXMLDocument)
...
end;
我有TDPR
另一个对象TXMLTree
(fIDocument
fIDocStart
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;
通常我使用fIDocument
andfIDocStart
作为到达 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;
如果我调用此过程,它会稍微增加内存使用量,但会定期调用它,内存耗尽只是时间问题。
但是:如果我使用fIDocStart
which 已经存储了所需的接口 - 所以不需要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)