многопоточность вызывает утечку памяти - PullRequest
0 голосов
/ 21 мая 2018

Я сделал приложение, которое получает данные от API каждые 10 секунд, и все это делается в 2 потока.Я не могу понять, почему происходит утечка памяти, поскольку я освобождаю все, что я использовал после выполнения задачи.

Я хочу извиниться, если я пропустил или делаю что-то не так, поскольку я новичок в потоке и не до конца понимаю, как это работает.

Я пытался переделать это: Синхронизация потоков и графического интерфейса в приложении Delphi , но не удалось, так как я не понимаю, что происходит.Если кто-то может объяснить мне, что я делаю не так и как я могу это исправить или сделать лучше.

Текущий код:

unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
  IdSSLOpenSSL, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL;

type
  TfrmMain = class(TForm)
    grpLuno: TGroupBox;
    lblBid: TLabel;
    lblRolling24HourVolume: TLabel;
    grpBinance: TGroupBox;
    tmrRefresh: TTimer;
    lblPrice: TLabel;
    lblBinanceVolume: TLabel;
    lbl1: TLabel;
    lbl24hChange: TLabel;
    procedure Refresh;
    procedure tmrRefreshTimer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TGetLuno = class(TThread)
  protected
    procedure Execute; override;
  end;

type
  TGetBinance = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

uses
  djson, DateUtils, Math;

{ TForm1 }

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NoMove or SWP_NoSize);
  Refresh;
end;

procedure TfrmMain.Refresh;
begin
  with TGetLuno.Create do
  begin
    FreeOnTerminate := True;
  end;

  with TGetBinance.Create do
  begin
    FreeOnTerminate := True;
  end;

end;

procedure TfrmMain.tmrRefreshTimer(Sender: TObject);
begin
  Refresh;
end;

{ TGetLuno }

procedure TGetLuno.Execute;
var
  httpclient: TIdHTTP;
  sdata: string;
  jdata: TJSON;
begin
  httpclient := TIdHTTP.Create(nil);
  try
    sdata := httpclient.Get('https://api.mybitx.com/api/1/ticker?pair=XBTZAR');
  finally
    httpclient.Free;
  end;

  jdata := TJSON.Parse(sdata);
  try
    frmMain.lblBid.Caption := 'Price: R ' + jdata['bid'].AsString;
    frmMain.lblRolling24HourVolume.Caption := 'Volume: ' + jdata['rolling_24_hour_volume'].AsString;
  finally
    jdata.Free;
  end;
end;

{ TGetBinance }

procedure TGetBinance.Execute;
var
  httpclient: TIdHTTP;
  sdata: string;
  jdata: TJSON;
  SocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  httpclient := TIdHTTP.Create(nil);
  SocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  SocketOpenSSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
  httpclient.IOHandler := SocketOpenSSL;
  try
    sdata := httpclient.Get('https://api.binance.com/api/v1/ticker/24hr?symbol=BTCUSDT');
  finally
    httpclient.Free;
  end;

  jdata := TJSON.Parse(sdata);
  try
    frmMain.lblPrice.Caption := 'Price: $ ' + jdata['lastPrice'].AsString;
    frmMain.lblBinanceVolume.Caption := 'Volume: ' + jdata['volume'].AsString;

    if StrToFloat(StringReplace(jdata['priceChangePercent'].AsString, '.', ',', [rfReplaceAll, rfIgnoreCase])) > 0 then
      frmMain.lbl24hChange.Font.Color := clLime
    else
      frmMain.lbl24hChange.Font.Color := clRed;
    frmMain.lbl24hChange.Caption := StringReplace(FloatToStr(RoundTo(StrToFloat(StringReplace(jdata['priceChangePercent'].AsString, '.', ',', [rfReplaceAll, rfIgnoreCase])), -2)), ',', '.', [rfReplaceAll, rfIgnoreCase]) + ' %';
  finally
    jdata.Free;
  end;
end;

initialization
  ReportMemoryLeaksOnShutdown := True;

end.

1 Ответ

0 голосов
/ 22 мая 2018

Внутри ваших методов выполнения потока вы обращаетесь к компонентам VCL frmMain напрямую.

Поскольку инфраструктура VCL должна выполняться только в главном потоке, вам потребуется перенаправить эти вызовы.Используйте TThread.Synchronize () или TThread.Queue () , например:

jdata := TJSON.Parse(sdata);
try
  Synchronize(
    procedure
    begin
      frmMain.lblPrice.Caption := 'Price: $ ' + jdata['lastPrice'].AsString;
      frmMain.lblBinanceVolume.Caption := 'Volume: ' + jdata['volume'].AsString;

      if StrToFloat(StringReplace(jdata['priceChangePercent'].AsString, '.',
        ',', [rfReplaceAll, rfIgnoreCase])) > 0 then
        frmMain.lbl24hChange.Font.Color := clLime
      else
        frmMain.lbl24hChange.Font.Color := clRed;
      frmMain.lbl24hChange.Caption :=
        StringReplace(FloatToStr(RoundTo(StrToFloat(StringReplace(jdata
        ['priceChangePercent'].AsString, '.', ',', [rfReplaceAll, rfIgnoreCase])
        ), -2)), ',', '.', [rfReplaceAll, rfIgnoreCase]) + ' %';
    end);
finally
  jdata.Free;
end;
...