【问题标题】:Memory leak, misuse of thread?内存泄漏,线程滥用?
【发布时间】:2020-04-01 17:08:33
【问题描述】:

我第一次尝试使用线程,但不知道为什么会出现内存泄漏,线程滥用的原因,或者导致我愚蠢而忘记释放某些东西,但在这一点上,我不知道, 是哪一个(或两者)。

这是点击时调用的过程

procedure TmainForm.scrollFrameClick(item:TEquipmentItem; itemFrame:TitemFrame);
begin
item.fullImage:=itemFrame.itemImage.Picture.Graphic;
setCurrentSearchItem(item);
end;

调用线程的过程

procedure TmainForm.setCurrentSearchItem(item:TEquipmentItem);
begin

if not(assigned(searchResultTable)) then
  searchResultTable:=TItemHtmlTable.Create
else
  begin
    freeandnil(searchResultTable);
    searchResultTable:=TItemHtmlTable.Create;
  end;

if getDomTh<>nil then
  if getDomTh.Finished then
    begin
      getDomTh.Terminate;
      getDomTh.WaitFor;
      FreeAndNil(getDomTh);
    end
  else
    begin
      getDomTh.WaitFor;
      getDomTh.Terminate;
      FreeAndNil(getDomTh);
    end;

getDomTh:=TCreateDomThread.Create(false,'http://www.example.com/ru/items/'+inttostr(item.ID),searchResultTable.DomTree);

currentItemImage.Picture.Graphic:=item.fullImage;
itemNameLab.Caption:=item.ItemName;
itemTypeLab.Caption:=item.ItemTypeName;
itemSubtypeLab.Caption:=item.ItemSubtypeName;

/////////////////
// At this point i would call a thread and use the result from the "searchResultTable"
/////////////////

if getDomTh<>nil then
  if getDomTh.Finished then
    freeandnil(searchResultTable)
  else
    begin
      getDomTh.WaitFor;
      getDomTh.Terminate;
      FreeAndNil(getDomTh);
      freeandnil(searchResultTable);
    end;
end;

这是线程单元

unit threadUnit;

interface

uses System.Classes,System.SysUtils, parser;

type
  TCreateDomThread = class(TThread)
  private
    pDomTree:TDomTree;
    pUrl:string;
  public
    property tDomTree:TDomTree read pDomTree write pDomTree;
    property tUrl:string read pUrl write pUrl;
    constructor Create(suspended:boolean; Url:string; DomTree:TDomTree);
    procedure Execute; override;
  end;

implementation

uses main;


constructor TCreateDomThread.Create(suspended:boolean; Url:string; DomTree:TDomTree);
begin
  tDomTree:=DomTree;
  tUrl:=Url;
  inherited Create(suspended);
end;

procedure TCreateDomThread.Execute;
begin
    if Terminated then Exit;
    mainForm.getDomTree(tUrl, tDomTree);
end;
end.

DomTree 检索

 procedure TmainForm.getDomTree(url:string; outputDomTree:TDomTree);
    var
      HtmlTxt: string;
    begin
      try
        HtmlTxt := IdHTTP1.Get(url);
        if not outputDomTree.RootNode.RunParse(HtmlTxt) then
          TThread.Queue(nil,procedure begin showmessage('Can'#39'tParse HTML!') end);
      except
        on E: Exception do
          TThread.Queue(nil,procedure begin ShowMessage(E.ClassName + ' : ' + E.Message); end);
      end;
    end;

如果您点击几次,taskmanager 会显示已提交的内存一直在增加。 我对调试没有运气,任何建议将不胜感激。

编辑:

所以有一堆TDomTree 不是免费的,但我不明白,从哪里导致线程按预期被破坏

Delphi memory manager screenshot

编辑 2: 发现错误。

【问题讨论】:

  • 您有什么证据表明内存泄漏? (不要依赖您认为 TaskMan 可能会告诉您的内容。)
  • 好吧,既然我可以点击 50 次并使用 100+ mb 的内存,我想,我可以称之为泄漏
  • 与内存泄漏无关,但setCurrentSearchItem的前七行可以单独替换为else分支中的两行。如果Xnil,那么做X.Free(因此FreeAndNil(X))是完全安全的。那是因为X.Free 基本上是if Assigned(X) then X.Destroy
  • 好的,谢谢

标签: multithreading delphi memory


【解决方案1】:

所以我发现了问题。在更新 ui 的线程中引用了来自 TDomTreeStringList。因此,当工作线程试图销毁searchResultTable 时,它的TDomTreeStringList 无法终止,产生异常,所以整个TDomTree 没有终止。

【讨论】:

    猜你喜欢
    • 2011-07-30
    • 2014-10-29
    • 2013-12-18
    • 2017-02-04
    • 2016-12-09
    • 2020-08-08
    • 2012-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多