Delphi:TAdoQuery 内存泄漏?

发布于 2024-09-29 07:22:24 字数 744 浏览 1 评论 0原文

我正在使用 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任务管理器时,查询后内存使用量不断上升而不是下降。

如何解决这个问题?

谢谢!

I'm developing as small diabetes program using Delphi 5 and ADO. I do a little query like this:

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;

The query runs OK and returns the result as expected. However, when I checked Windows Task Manager, memory usage keeps on rising rather than decreasing after the query.

How to fix this?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

|煩躁 2024-10-06 07:22:24

您首先将 TADOQuery 设置为 nil,然后对 nil 变量调用 Free(这不会执行任何操作),从而泄漏了 TADOQuery

You are leaking the TADOQuery by first setting it to nil, and then calling Free on the nil variable (which does nothing)

鹊巢 2024-10-06 07:22:24
  • 您安装了 Delphi 5 更新吗?这
    RTM ADO 实现众所周知
    有问题。
  • 使用 FastMM4,它应该与
    Delphi 5 也是如此,并告诉您更多
    关于泄漏的地方。
  • Did you install Delphi 5 updates? The
    RTM ADO implementation is known to
    have issues.
  • Use FastMM4, it should work with
    Delphi 5 as well, and tell you more
    about where the leaks are.
薄凉少年不暖心 2024-10-06 07:22:24

德尔福方式:

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;

The Delphi way:

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;
简单爱 2024-10-06 07:22:24

引用:

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

你在开玩笑吧?首先将变量置零,然后释放它?你真是个天才! :-)

使用:

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

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


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

Quote:

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

You're kidding, right? First nil the variable, then free it? You're a genius! :-)

Use:

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

Or don't even bother assigning nil to it, since Q is a local variable...


But rereading your code, I notice you use Application as owner. As a result, it will not really be a leak, since it will be freed when the application is freed. If you use a form, it would be freed when the owner form gets freed.
What you should try is to call this query about 100.000 times to check if it keeps reserving memory or if it's just increasing memory until a certain size has been reached. The latter is more likely, since the memory is reserved for future ADO calls.

一个人的旅程 2024-10-06 07:22:24

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

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

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

除此之外,任务管理器对于确定内存使用情况来说是一个糟糕的工具。您可能会释放 Q 的内存,但这并不自动意味着 Delphi 内存管理器将内存释放给操作系统。

As others pointed out, the finally section should have the 2 statements reversed, like so:

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

Or you can call SysUtils.FreeAndNil(Q) (if that is available in Delphi 5, not sure).

Beside that, the TaskManager is an awful instrument to determine memory usage anyway. You might release the memory for Q, but that does not automatically mean the Delphi memory manager releases the memory to the OS.

北凤男飞 2024-10-06 07:22:24

除了将行反转为 Arjan 之外,jasonpennyWorkShop Alex说,你可以使用Process Explorer查看进程的实际内存消耗(私有字节)。任务管理器并不真正适合此任务,因为它仅显示进程的工作集。

Aside inversing the lines as Arjan, jasonpenny and WorkShop Alex said, you can use Process Explorer to see the real consumption of memory (Private Bytes) of the process. Task Manager is not really suited to this task, as it only shows the working set of the process.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文