2014-07-15 48 views
0

我有一个程序接受SQL查询作为命令行参数,查询PostgreSQL数据库并生成一个文件格式为多种方式之一(通常用于生成CSV文件)。字符串中的Delphi内存泄漏?

但是,该程序有严重的内存泄漏 - 一个特定的查询生成12MB文件,该程序使用8GB的RAM加上几GB的交换空间,然后操作系统将其杀死。我想找到这个内存泄漏的原因。我不太了解德尔菲(根据程序的质量来判断,原作者也没有),但我的任务是找到一个快速解决方案。

以下doData函数部分输出一行结果集。我猜测问题出在“复制”命令的问题上(在堆上创建一个永远不会释放的字符串),但我确定有人比我更有经验能够确认这个答案,或者指向我正确的方向。

procedure doData; 
var 
    s, fldVal : string; 
    i, fldLen : integer; 
begin 
    s := ''; 

    for i := 0 to ds.Fields.Count-1 do 
    begin 
     if (ds.Fields[i].DataType = ftDate) or 
      (ds.Fields[i].DataType = ftDateTime) then 
     begin 
      if psql.outDate = 'i' then 
       fldLen := 8 
      else 
       fldLen := 10; 

      if ds.Fields[i].IsNull then 
       fldVal := '' 
      else 
       fldVal := formatDate(ds.Fields[i].AsDateTime); 
     end 
     else 
     begin 
      fldLen := ds.Fields[i].DisplayWidth; 
      fldVal := ds.Fields[i].AsString; 
     end; 

     if (psql.outType = 'd') or (psql.outType = 's') then 
      s := s + trim(fldVal) 

     else if psql.outType = 'f' then 
     begin 
      s := s + fldVal; 

      if fldLen - length(fldVal) > 0 then 
       s := s + copy(spaces, 1, fldLen - length(fldVal)); 
       // Is this a memory leak above? 
     end; 

     if psql.outType = 's' then 
     begin 
      if i < ds.Fields.Count-1 then 
      s := s + psql.outDelimChar; 
     end 
     else 
      s := s + psql.outDelimChar; 
    end; 

    writeln(psql.outPrefixData + s); 
end; 
+1

德尔福字符串类型与参考计数管理。当一个字符串变量超出范围时,它会自动销毁。 'Copy'不能在这段代码中产生内存泄漏。 –

+1

如果你生产的是12MB的字符串,那么你做错了事情:改用TStringBuilder(或直接写入流)。但使用's:= s + xx'这样的代码对于内存处理来说是非常糟糕的 – Daniel

+0

我发现'MadExcept'是识别内存泄漏的有效工具,但是从你的代码片段开始,我可能会检查'ds'和'psql'得到释放 - 你可能会很幸运...... –

回答

4

此代码没有泄漏。 Delphi string类型由编译器管理,不需要程序员明确的内存释放。

如果你想找到你的泄漏,你应该包括完整的调试版本FastMM。这将产生诊断报告,包括代码中任何泄漏的信息,包括帮助识别泄漏内存最初分配位置的堆栈跟踪。