我做了一个应用程序,每隔10秒从API接收数据,这都是在2个线程内完成的。我无法弄清楚为什么会出现内存泄漏,因为我在任务完成后释放了我所使用的所有东西。
如果我因为线程新手而错过或做错事我想道歉,而且我不完全理解它是如何工作的。
我试图重拍这个:Synchronizing Threads and GUI in a Delphi Application但失败了,因为我不明白发生了什么。如果有人能够向我解释我做错了什么以及如何解决或改善它。
当前代码:
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.
答案 0 :(得分:3)
在线程执行方法中,您直接访问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;