1

我正在使用 Delphi 5 和 ADO 开发小型糖尿病程序。我做了一个这样的小查询:

function GetLowestGlucoseLevel(StartDate:string;EndDate:string): Integer;
var
  Q:TADOQuery;
begin
   try
      Q:=TADOQuery.Create(Application); //Separate unit, owner set to App
      Q.Connection:=dtMod.ADOCon;
      Q.DisableControls;
      Q.Close;
      Q.SQL.Clear;
      Q.SQL.Add('SELECT Min(qGlucose.Glucose) AS MinOfGlucose from qGlucose');
      Q.Parameters[0].Value:=StartDate;
      Q.Parameters[1].Value:=EndDate;
      Q.Open;

      Result:=Q.FieldByName('MinOfGlucose').AsInteger;

      Q.Close;
    finally
      Q:=nil;
      Q.Free; 
    end; 
end;

查询运行正常并按预期返回结果。但是,当我检查 Windows 任务管理器时,查询后内存使用量持续上升而不是下降。

如何解决这个问题?

谢谢!

4

6 回答 6

13

TADOQuery首先将其设置为 nil,然后调用Freenil 变量(它什么都不做)来泄漏

于 2010-10-27T13:51:06.380 回答
4
  • 您是否安装了 Delphi 5 更新?已知 RTM ADO 实现存在问题。
  • 使用 FastMM4,它应该也可以与 Delphi 5 一起使用,并告诉您更多有关泄漏位置的信息。
于 2010-10-27T14:20:28.647 回答
3

德尔福方式:

function GetLowestGlucoseLevel(const StartDate:string; const EndDate:string): Integer;
var
  Q:TADOQuery;

begin

    Q:=TADOQuery.Create(nil); //(nil) because local use only. Placed before try\finally block 
                              //because if it fails to .create then there would be no object to
                              //.Free 
    try

      Q.Connection := dtMod.ADOCon;

      //------can erase these------
      //Q.DisableControls; //No controls attached so unnecessary
      //Q.Close;           //Q is local and was never opened so no need to close
      //Q.SQL.Clear;       //Q is local and was never filled so no need to clear

      Q.SQL.Add('SELECT Min(qGlucose.Glucose) AS MinOfGlucose from qGlucose');
      Q.Parameters[0].Value:=StartDate;
      Q.Parameters[1].Value:=EndDate;
      Q.Open;

      Result := Q.FieldByName('MinOfGlucose').AsInteger;

      Q.Close;

    finally 

      Q.Free;

      //Q := nil          //not needed because Q's scope is local

    end; 
end;
于 2011-08-14T00:14:58.673 回答
2

引用:

finally
  Q:=nil;
  Q.Free; 
end; 

你开玩笑的对吧?首先 nil 变量,然后释放它?你真是个天才!:-)

利用:

finally
  Q.Free; 
  Q:=nil;
end; 

或者甚至不用为它分配 nil ,因为 Q 是一个局部变量......


但是重新阅读您的代码,我注意到您使用 Application 作为所有者。因此,它不会是真正的泄漏,因为它会在应用程序被释放时被释放。如果您使用表单,它将在所有者表单被释放时被释放。
您应该尝试调用此查询大约 100.000 次,以检查它是否继续保留内存,或者是否只是增加内存直到达到特定大小。后者更有可能,因为内存是为将来的 ADO 调用保留的。

于 2010-10-27T14:32:12.173 回答
0

正如其他人指出的那样,finally 部分应该将 2 个语句颠倒过来,如下所示:

finally
  Q.Free; 
  Q:=nil;  // <- not even necessary since this is a local var
end; 

或者您可以调用 SysUtils.FreeAndNil(Q) (如果在 Delphi 5 中可用,则不确定)。

除此之外,TaskManager 无论如何都是确定内存使用情况的糟糕工具。您可能会为 Q 释放内存,但这并不意味着 Delphi 内存管理器会自动将内存释放给操作系统。

于 2010-10-27T14:10:07.207 回答
0

除了像ArjanjasonpennyWorkShop Alex所说的那样,您可以使用Process Explorer查看进程的实际内存消耗(Private Bytes)。任务管理器并不真正适合这项任务,因为它只显示流程的工作集。

于 2010-10-27T16:05:16.730 回答