TStringList和TThread没有释放所有内存

Van*_*laH 4 memory delphi ram tstringlist tthread

使用的版本: Delphi 7.

我正在开发一个在Virtual ListView上执行简单for循环的程序.数据存储在以下记录中:

type TList=record
  Item:Integer;
  SubItem1:String;
  SubItem2:String;
end;
Run Code Online (Sandbox Code Playgroud)

项目是索引.SubItem1操作的状态(成功与否).SubItem2文件的路径.在循环加载每个文件,做一些操作,然后保存.操作发生在TStringList中.文件大约每个2mb.

现在,如果我在主窗体上执行操作,它可以完美地工作.

多线程,存在巨大的内存问题.不知何故,TStringList似乎没有被完全释放.在3-4k文件之后,我得到一个EOutofMemory异常.有时候,软件会停留在500-600mb,有时候不会.在任何情况下,TStringList始终返回EOutofMemory异常,并且不再可以加载任何文件.在具有更多内存的计算机上,获取异常需要更长时间.

其他组件也会发生同样的事情.例如,如果我使用Synapse的THTTPSend,过了一段时间,软件无法创建任何新线程,因为内存消耗太高.它大概是500-600mb,而它应该是,最大,100mb.在主窗体上,一切正常.

我想这个错误就在我身边.也许我不太了解线程.我试图释放Destroy事件中的所有内容.我尝试过FreeAndNil程序.我一次只尝试一个线程.我尝试手动释放线程(没有FreeOnTerminate ......)

没运气.

所以这是线程代码.这只是基本的想法; 不是所有操作的完整代码.如果我删除LoadFile prodecure,一切都很好.根据线程池为每个文件创建一个线程.

unit OperationsFiles;

interface

uses Classes, SysUtils, Windows;

type
 TOperationFile = class(TThread)
 private
  Position : Integer;
  TPath, StatusMessage: String;
  FileStringList: TStringList;
  procedure UpdateStatus;
  procedure LoadFile;
 protected
  procedure Execute; override;
 public
  constructor Create(Path: String; LNumber: Integer);
 end;

implementation

uses Form1;

procedure TOperationFile.LoadFile;
begin
 try
  FileStringList.LoadFromFile(TPath);
  // Operations...
  StatusMessage := 'Success';
 except
  on E : Exception do StatusMessage := E.ClassName;
 end;
end;

constructor TOperationFile.Create(Path : String; LNumber: Integer);
begin
 inherited Create(False);
 TPath := Path;
 Position := LNumber;
 FreeOnTerminate := True;
end;

procedure TOperationFile.UpdateStatus;
begin
 FileList[Position].SubItem1 := StatusMessage;
 Form1.ListView4.UpdateItems(Position,Position);
end;

procedure TOperationFile.Execute;
begin
 FileStringList:= TStringList.Create;
 LoadFile;

 Synchronize(UpdateStatus);

 FileStringList.Free;
end;

end.
Run Code Online (Sandbox Code Playgroud)

可能是什么问题呢?

我曾想过,也许创建了太多的线程.如果用户加载了100万个文件,那么最终将创建100万个线程 - 尽管只创建并运行 50个线程.

感谢您的输入.

Dav*_*nan 7

您在问题中显示的代码中(可能)没有泄漏.

我说可能是因为在此期间引发的异常Execute可能导致泄漏.字符串列表的生命周期应该由finally块保护.

FileStringList:= TStringList.Create;
try
  LoadFile;
  Synchronize(UpdateStatus);
finally
  FileStringList.Free;
end;
Run Code Online (Sandbox Code Playgroud)

也就是说,我希望吞下异常LoadFile意味着你不会泄漏字符串列表.

你说可能创建了数千个线程.每个线程为其堆栈保留内存,默认堆栈大小为1MB.一旦预留了数千个1MB堆栈,就可以轻松耗尽或分割地址空间.

我看到过去由于骑士创造线程而导致的问题.例如,我有一个程序在创建和销毁线程时失败,存在的线程数不超过256个.这是一台16核的机器,有4GB的地址空间.您可能有2GB的地址空间.

虽然你说任何时刻都存在不超过50个线程,但我不确定你怎么能确定它.并非最不重要的,因为你已经设置FreeOnTerminateTrue,从而交出了控制自己的线程的寿命.

我的猜测是你的问题与你创建的线程数有关.每个处理器一个线程就足够了.重用你的线程.为小型任务创建和销毁线程的成本很高.

如果这还不足以解决您的问题,那么您将需要显示管理线程生命周期的代码.

最后,我想知道你将从这个应用程序线程中提取多少好处.如果它是IO绑定,则线程版本可能会更慢!