2

我正在使用 Delphi 从关系数据库中的数据创建 XML 文档。它在小型数据集上测试良好,但是当我尝试将数据集的大小扩展到生产级别时,它最终在节点创建期间出现 EOutOfMemory 异常。

我正在使用放置在表单上的 TXMLDocument(MSXML 作为供应商),我的代码通常如下所示:

  DS := GetDS(Conn, 'SELECT Fields. . . FROM Table WHERE InsuredID = ' +IntToStr(AInsuredID));

  try

    while not DS.Eof do
      with ANode.AddChild('LE') do
      begin
        AddChild('LEProvider').Text := DS.FieldByName('LEProvider').AsString;
        // Need to handle "other" here
        AddChild('Date').Text       := DateToXMLDate(DS.FieldByName('LEDate').AsDateTime);
        AddChild('Pct50').Text      := DS.FieldByName('50Percent').AsString;
        AddChild('Pct80').Text      := DS.FieldByName('80Percent').AsString;
        AddChild('Actuarial').Text  := DS.FieldByName('CompleteActuarial').AsString;
        AddChild('Multiplier').Text := DS.FieldByName('MortalityMultiplier').AsString;
        DS.Next;
      end;

  finally

    DS.Free;

  end;

这个部分以及许多其他类似构造的部分适用于不同的数据库表,执行了很多次。在此示例中,ANode 是传递给函数以用作容器的 IXMLNode。

我不希望磁盘上生成的 XML 文件超过 10 兆字节。我假设我在创建和处理 XMLNodes 时以某种方式泄漏了内存,但我对接口不够熟悉,不知道如何追踪我的问题。

4

3 回答 3

3

TXMDocument 是一个 DOM 风格的界面,将整个文档保存在内存中。那样内存会很快用完。即使生成的文件不是那么大。您实际上并不需要 TXMLDocument 来写出一个简单的 XML。为什么不直接写入 xml 格式的文件?

话虽这么说:这也可能是由于堆碎片或真正的内存泄漏而导致的错误。您可能想尝试这里提到的工具:Delphi 的 Profiler and Memory Analysis Tools

于 2009-09-30T18:43:32.913 回答
0

这些调用中的每一个都将其结果存储到编译器隐式声明AddChild的临时变量中。IXmlNode当当前子例程返回时(无论是正常还是异常),它们应该被自动清理。您可以通过声明自己的变量来使它们的生命周期更加明确。

var
  le, child: IXmlNode;
begin
  DS := GetDS(Conn, Format(Query, [AInsuredID]));
  try
    while not DS.Eof do begin
      le := ANode.AddChild('LE');
      child := le.AddChild('LEProvider');
      child.Text := DS.FieldByName('LEProvider').AsString;
      // Need to handle "other" here
      child := le.AddChild('Date');
      child.Text := DateToXMLDate(DS.FieldByName('LEDate').AsDateTime);
      child := le.AddChild('Pct50');
      child.Text := DS.FieldByName('50Percent').AsString;
      child := le.AddChild('Pct80');
      child.Text := DS.FieldByName('80Percent').AsString;
      child := le.AddChild('Actuarial');
      child.Text := DS.FieldByName('CompleteActuarial').AsString;
      child := le.AddChild('Multiplier');
      child.Text := DS.FieldByName('MortalityMultiplier').AsString;
      DS.Next;
    end;
  finally
    DS.Free;
  end;
end;

在上面的代码中,没有隐式的接口变量。编译器会为每个AddNode调用声明一个新的隐式变量,但上面的代码表明只有两个是必需的,因为child可以为每个新的子节点重用。

不过,仅此代码不应该导致大量的内存使用。您似乎更有可能保留对不再需要的对象的引用,或者您正在为某些接口对象创建循环引用。MSXML 库不应该创建它自己的任何循环引用,但是您还没有显示所有可能在此处运行的代码。

于 2009-09-30T18:50:36.503 回答
0

尝试使用 SAX 解析器而不是 DOM。DOM 将整个 XML 文件的表示形式保存在内存中。

在这里试试

于 2009-09-30T22:12:45.463 回答