内存泄漏和 JSON 数据
Memory leaks and JSON data
我有一个应用程序,它从磁盘读取 JSON 数据字符串以创建一个字符串网格列表股票(代码、持有数量、成本),然后调用股票经纪人 API 来填写当前价格和价值。它可以工作,但下面的代码会导致内存泄漏,但是虽然有很多关于如何访问 JSON 数组 none 中的数据的互联网帖子,但我可以找到讨论如何释放分配的内存。有人可以帮忙吗?如果重要的话,我使用 Delphi Berlin 10.1 和 Indy 10.6。有 3 页数据,一些股票在 2 页上,sTickers 是一个字符串列表,其中填充了每个股票代码(大约 10 个),并且 3 个字符串网格(tabGrids[0..2] 上大约有 14 个股票持有量在页面控件上。
问题代码为:
JSONArray := TJSONObject.ParseJSONValue(s) as TJSONArray;
if JSONarray = nil then
begin
ShowMessage('An error occurred reading the data file, section = [' +
iniSection[tabpage] + '].');
continue;
end;
for row := 0 to JSONArray.Count - 1 do
begin
s := (JSONArray.Items[row] as TJSONObject).Get('ticker').JSONValue.Value;
SL.Add(s);
end;
CombineStrings(sTickers, SL);
tabGrids[tabpage].RowCount := SL.Count + 2; //set row count
for row := 1 to SL.Count do
begin //add fixed data to each grid row
tabGrids[tabpage].Cells[0, row] := SL[row - 1];
tabGrids[tabpage].Cells[4, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('qty').JSONValue.Value;
tabGrids[tabpage].Cells[6, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('cost').JSONValue.Value;
tabGrids[tabpage].Cells[1, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('name').JSONValue.Value;
if not tryStrToFloat(tabGrids[tabpage].Cells[4, row], qty) then qty := 0;
if not tryStrToFloat(tabGrids[tabpage].Cells[6, row], price) then price := 0;
tabGrids[tabpage].Cells[6, row] := FloatToStr(qty*price/100);
end;
tabGrids[tabpage].Width := tabGrids[tabpage].ColWidths[0] +
tabGrids[tabpage].ColWidths[1] + tabGrids[tabpage].ColWidths[2] +
tabGrids[tabpage].ColWidths[3] + tabGrids[tabpage].ColWidths[4] +
tabGrids[tabpage].ColWidths[5] + tabGrids[tabpage].ColWidths[6] + 18;
SL.Clear;
end;
JSONArray.Free;
我假设 (JSONArray.Items[row] as TJSONObject).Get('ticker').JSONValue.Value 行正在分配我不会释放的内存但我不知道如何释放它。或者,也许有更好的方法来获取数据。
您提到了 3 页数据。您正在泄漏 2 x TJasonArray
,并且在没有相应开始的 end;
之后的最后一行释放了一个 TJasonArray
。
据此我得出结论,您有一个循环(您没有显示)您 运行 三次。每次创建 TJasonArray
但只释放一个时,在循环 end;
之后,将 JSonArray.Free;
移动到 end;
.
之前
为了更简单,您可以只使用 TJSONValue
来解析并在最后释放它,而无需释放数组:[=16=]
var
Value: TJsonValue
// ...
begin
Value := TJSONObject.ParseJSONValue(s);
try
Ar := Value.FindValue('item') as TJSONArray;
finally
FreeAndNil(Value);
end;
end;
而不是:
tabGrids[tabpage].Cells[1, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('name').JSONValue.Value;
你可以做到
tabGrids[tabpage].Cells[1, row] := JSONArray.Items[row - 1].GetValue<string>('name');
然后,在释放数组之前有一个 end;
,如果它是上层循环,您将有内存泄漏。使用 try finally 块来释放它和 TStringList
.
我有一个应用程序,它从磁盘读取 JSON 数据字符串以创建一个字符串网格列表股票(代码、持有数量、成本),然后调用股票经纪人 API 来填写当前价格和价值。它可以工作,但下面的代码会导致内存泄漏,但是虽然有很多关于如何访问 JSON 数组 none 中的数据的互联网帖子,但我可以找到讨论如何释放分配的内存。有人可以帮忙吗?如果重要的话,我使用 Delphi Berlin 10.1 和 Indy 10.6。有 3 页数据,一些股票在 2 页上,sTickers 是一个字符串列表,其中填充了每个股票代码(大约 10 个),并且 3 个字符串网格(tabGrids[0..2] 上大约有 14 个股票持有量在页面控件上。
问题代码为:
JSONArray := TJSONObject.ParseJSONValue(s) as TJSONArray;
if JSONarray = nil then
begin
ShowMessage('An error occurred reading the data file, section = [' +
iniSection[tabpage] + '].');
continue;
end;
for row := 0 to JSONArray.Count - 1 do
begin
s := (JSONArray.Items[row] as TJSONObject).Get('ticker').JSONValue.Value;
SL.Add(s);
end;
CombineStrings(sTickers, SL);
tabGrids[tabpage].RowCount := SL.Count + 2; //set row count
for row := 1 to SL.Count do
begin //add fixed data to each grid row
tabGrids[tabpage].Cells[0, row] := SL[row - 1];
tabGrids[tabpage].Cells[4, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('qty').JSONValue.Value;
tabGrids[tabpage].Cells[6, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('cost').JSONValue.Value;
tabGrids[tabpage].Cells[1, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('name').JSONValue.Value;
if not tryStrToFloat(tabGrids[tabpage].Cells[4, row], qty) then qty := 0;
if not tryStrToFloat(tabGrids[tabpage].Cells[6, row], price) then price := 0;
tabGrids[tabpage].Cells[6, row] := FloatToStr(qty*price/100);
end;
tabGrids[tabpage].Width := tabGrids[tabpage].ColWidths[0] +
tabGrids[tabpage].ColWidths[1] + tabGrids[tabpage].ColWidths[2] +
tabGrids[tabpage].ColWidths[3] + tabGrids[tabpage].ColWidths[4] +
tabGrids[tabpage].ColWidths[5] + tabGrids[tabpage].ColWidths[6] + 18;
SL.Clear;
end;
JSONArray.Free;
我假设 (JSONArray.Items[row] as TJSONObject).Get('ticker').JSONValue.Value 行正在分配我不会释放的内存但我不知道如何释放它。或者,也许有更好的方法来获取数据。
您提到了 3 页数据。您正在泄漏 2 x TJasonArray
,并且在没有相应开始的 end;
之后的最后一行释放了一个 TJasonArray
。
据此我得出结论,您有一个循环(您没有显示)您 运行 三次。每次创建 TJasonArray
但只释放一个时,在循环 end;
之后,将 JSonArray.Free;
移动到 end;
.
为了更简单,您可以只使用 TJSONValue
来解析并在最后释放它,而无需释放数组:[=16=]
var
Value: TJsonValue
// ...
begin
Value := TJSONObject.ParseJSONValue(s);
try
Ar := Value.FindValue('item') as TJSONArray;
finally
FreeAndNil(Value);
end;
end;
而不是:
tabGrids[tabpage].Cells[1, row] := (JSONArray.Items[row - 1] as TJSONObject).Get('name').JSONValue.Value;
你可以做到
tabGrids[tabpage].Cells[1, row] := JSONArray.Items[row - 1].GetValue<string>('name');
然后,在释放数组之前有一个 end;
,如果它是上层循环,您将有内存泄漏。使用 try finally 块来释放它和 TStringList
.