【问题标题】:Does this delphi code has memory leak?这个delphi代码有内存泄漏吗?
【发布时间】:2016-08-30 07:32:20
【问题描述】:

有两个用 Delphi 编写的服务。一项服务在服务器上运行,而另一项服务在客户端上运行。这两个服务进行通信以在客户端和服务器之间交换数据。在这种情况下,服务器服务要求客户​​端发送数据,但是大约一天后,服务器上分配的内存超过了它的物理大小。经过一番研究,我发现下面这两个函数有问题。

以下代码是否存在内存泄漏?

服务器服务:

function TServerMethods.LogInMngr_GetAllUsers(): TList<TLogInClass>;
Var
  C: TDBXCommand;
Begin
  C := CreateCommand('LogInMngr_GetAllUsers');
  try
    C.ExecuteUpdate;
    Result := GetValue<TList<TLogInClass>>(C.Parameters[RP]);
  finally
    C.Free;
  end;
end;

客户服务:

function TLogInMngrClass.GetAllUsers(status: TLogInStatus = lisUnknown): TList<TLogInClass>;
var
  LogIn: TLogInItem;
  LogInTemp: TLogInClass;
  UsedProg:  TUsedItem;
begin
  Result := TList<TLogInClass>.Create;

  for LogIn in LogInList do
    if (status = lisUnknown) or (LogIn.Status = Integer(status)) then
      for UsedProg in LogIn.UsedProgList do
      begin
        LogInTemp:=TLogInClass.Create(LogIn.ClientID, LogIn.ComputerName, LogIn.UserName, '', '');
        LogInTemp.LogInTime := DateTimeToFileTime(UsedProg.AccessTime);
        LogInTemp.Status := LogIn.Status;
        LogInTemp.ProgName := UsedProg.ItemName;
        LogInTemp.ProgVersion := UsedProg.ItemInfo;

        Result.Add(LogInTemp);
      end;
end;

数据在TLogInClass 类中,结果使用TDSServer 作为TLogInClass 类的通用列表返回。

【问题讨论】:

  • "这个 delphi 代码是否存在内存泄漏?" 可能是的,但在您发布的代码中没有证据表明这一点。没有证据表明TList&lt;TLogInClass&gt; 是如何被释放的。它也应该是一个拥有价值的TObjectList,但这只是一个猜测,就像答案一样
  • 您没有显示两个结果 TList&lt;TLogInClass&gt; 是如何被释放的。请添加此信息。
  • 要么生成minimal reproducible example,要么进行一些调试。

标签: delphi memory memory-management memory-leaks


【解决方案1】:

正如其他人所提到的,您没有展示客户端函数的“结果”是如何进行内存管理的。

我怀疑 GetAllUsers 作为客户端被多次调用,这反过来又会触发 Create 多次,这会增加内存消耗。

除此之外,我总是发现很难管理函数返回的对象。很难确定应该如何以及何时释放“结果”以及它们是否被释放。

目前,服务器端功能不“知道”谁负责管理结果。

我会将该函数重写为具有如下参数的过程:

procedure TServerMethods.LogInMngr_GetAllUsers (var userList: TObjectList<TLogInClass>);
begin
  if not assigned(userList) then 
    raise Exception.Create('userList not instantiated');
  ...
end;

然后调用这个过程:

var     
  tmpUsers: TObjectList<TLogInClass>;
begin
 tmpUsers:=TObjectList<TLogInClass>.Create;
 try
   ServerMethods.LogInMngr_GetAllUsers(tmpUsers); <--- or whatever you call the ServerMethods class
   .....
 finaly
   tmpUsers.Free;
 end;

结束;

这样您可以清楚地管理列表的生命周期。

也许我没有遵循您的设计或遗漏了一些内容,但我认为您明白了使用过程而不是函数来管理对象的意义。

【讨论】:

  • 返回新实例的函数没有问题,只要它们在名称中包含 Create 以指示它们创建新实例。像对待构造函数一样对待它们。如果出现异常,您所谓的改进泄漏。你最终需要尝试。
  • @DavidHeffernan:我没有说他们不好。我说管理 IMO 更容易。谢谢你的观点。我现在编辑了代码,它是“双重”所谓的改进
【解决方案2】:

你可以用这个轻松找到...

Memory Leak Notification in Delphi

  ReportMemoryLeaksOnShutdown := DebugHook <> 0;         

【讨论】:

  • 这不会找到所有泄漏。不会发现在执行期间应该释放内存的泄漏,只有在关机时才释放。对于长时间运行的进程很重要。
猜你喜欢
  • 1970-01-01
  • 2012-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 2016-08-27
相关资源
最近更新 更多