Warm tip: This article is reproduced from serverfault.com, please click

delphi-从内存中清除动态FMX列表视图位图

(delphi - Clearing Dynamic FMX listview bitmaps from memory)

发布于 2020-11-28 23:44:55

我最近开始处理动态列表视图项。很棒,除了我尝试用位图添加和清除项目时。我有一个listview,在其中添加项目并将图像下载到内存流中,并将其分配给动态listview项目的位图。除了我用lv.items.clear清除所有项目时,它不会从内存中删除,这是可行的。

即使我清除了旧项目,内存也一直在增加。有没有办法清除所有位图?

基本上发生的是:

  1. 用10个项目填充动态列表视图。添加数据和位图。
  2. 看一下记忆。用了2兆字节。
  3. 使用lv.items.clear清除listview。
  4. 看一下记忆。没有变化?
  5. 重复一次,内存就会不断增加。

我尝试遍历所有列表视图项并将每个位图设置为,nil但没有任何内存更改的结果。我还尝试通过循环释放每个项目,但这只会使应用程序崩溃。

我应该以某种方式清除所有项目或位图吗?如果是这样,我该怎么做呢?

这是我加载所有项目的方式:

procedure TPluginInstaller.Load;
begin
  with frmMain.framePluginManager do
  begin
    TThread.CreateAnonymousThread(
      procedure
      begin
        var restClient := TRESTClient.Create(nil);
        var restRequest := TRESTRequest.Create(nil);
        var restResponse := TRESTResponse.Create(nil);
        try
          restRequest.Client := restClient;
          restRequest.Response := restResponse;

          restClient.BaseURL := BASE_URL;
          restClient.UserAgent := APP_USERAGENT;
          restRequest.AddParameter('query', fQuery);
          restRequest.AddParameter('page', fPage.ToString);
          restRequest.AddParameter('sort', SortBy[fSort]);

          if fSort = 0 then
            restRequest.AddParameter('sortdir', 'asc')
          else
            restRequest.AddParameter('sortdir', 'desc');

          restRequest.AddParameter('categories[]', 'rust');

          restRequest.Execute;

          var jdata := restResponse.JSONValue;

          fLastPage := jdata.GetValue<Integer>('last_page', 1);
          fPage := jdata.GetValue<Integer>('current_page', 1);

          TThread.Synchronize(nil,
            procedure
            begin
              spnedtPage.Max := fLastPage;
              spnedtPage.Value := fPage;
              lblPageMax.Text := ' of ' + fLastPage.ToString;

              lvPluginInstaller.BeginUpdate;
              try
                lvPluginInstaller.Items.Clear;

                for var jplugins in (jdata.FindValue('data') as TJSONArray) do
                begin
                  var aItem := lvPluginInstaller.Items.Add;

                  var aIcon := aItem.Objects.FindObjectT<TListItemImage>('Icon');
                  var aDownloadsIcon := aItem.Objects.FindObjectT<TListItemImage>('DownloadsIcon');
                  var aVersionIcon := aItem.Objects.FindObjectT<TListItemImage>('VersionIcon');
                  var aAuthorIcon := aItem.Objects.FindObjectT<TListItemImage>('AuthorIcon');
                  var aUpdatedIcon := aItem.Objects.FindObjectT<TListItemImage>('UpdatedIcon');

                  var aTitle := aItem.Objects.FindObjectT<TListItemText>('Title');
                  var aDescription := aItem.Objects.FindObjectT<TListItemText>('Description');
                  var aVersion := aItem.Objects.FindObjectT<TListItemText>('Version');
                  var aDownloads := aItem.Objects.FindObjectT<TListItemText>('Downloads');
                  var aAuthor := aItem.Objects.FindObjectT<TListItemText>('Author');
                  var aURL := aItem.Objects.FindObjectT<TListItemText>('URL');
                  var aUpdated := aItem.Objects.FindObjectT<TListItemText>('Updated');

                  GetIcon(jplugins.GetValue<string>('icon_url').Trim, aIcon);

                  aDownloadsIcon.ImageIndex := 0;
                  aVersionIcon.ImageIndex := 1;
                  aAuthorIcon.ImageIndex := 2;
                  aUpdatedIcon.ImageIndex := 4;

                  aTitle.Text := jplugins.GetValue<string>('title', 'Unknown Plugin Title');
                  aDescription.Text := jplugins.GetValue<string>('description', 'Unknown Plugin Description');
                  aVersion.Text := jplugins.GetValue<string>('latest_release_version_formatted', 'Unknown Version');
                  aDownloads.Text := jplugins.GetValue<string>('downloads_shortened', 'Unknown Downloads');
                  aAuthor.Text := jplugins.GetValue<string>('author', 'Unknown Author');
                  aURL.Text := jplugins.GetValue<string>('json_url', 'Unknown URL');
                  aUpdated.Text := jplugins.GetValue<string>('latest_release_at', 'Unknown');
                end;
              finally
                lvPluginInstaller.EndUpdate;
              end;
            end);

        finally
          restResponse.Free;
          restRequest.Free;
          restClient.Free;
        end;
      end).Start;
  end;
end;

从网址加载位图:

procedure TPluginInstaller.GetIcon(const aURL: string; aIcon: TListItemImage);
begin
  if aURL = '' then
  begin
    aIcon.ImageIndex := 3;
    Exit;
  end;

  TThread.CreateAnonymousThread(
    procedure
    begin
      var imgStream := TMemoryStream.Create;
      try
        TDownloadURL.DownloadRawBytes(aURL, imgStream);

        TThread.Synchronize(nil,
          procedure
          begin
            aIcon.Bitmap := TBitmap.CreateFromStream(imgStream);
          end);

      finally
        imgStream.Free;
      end;
    end).Start;
end;
Questioner
Adriaan
Viewed
11
Remy Lebeau 2020-11-29 08:00:48

TListItemImage.OwnsBitmap属性设置为True,否则TBitmap使用对象后,你有责任手动释放对象。请注意,从Delphi 10.4开始,ARC不再用于移动平台上的对象内存管理

统一内存管理

  • 现在,使用对象内存管理的经典实现,Delphi内存管理已在所有受支持的平台(移动,桌面和服务器)之间进行了统一。与自动引用计数(ARC)相比,它与现有代码更好地兼容,并且为组件,库和最终用户应用程序提供了更简单的编码。ARC模型保留用于所有平台的字符串管理和接口类型引用。
  • 对于C ++,此更改意味着C ++中的Delphi样式类的创建和删除与任何堆分配的C ++类一样,遵循正常的内存管理,从而显着降低了复杂性。