使用 Delphi TJSONObject和TJSONArray的内存泄漏或访问冲突

v440hwme  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(218)

我在一个 Delphi Windows应用程序中有一个简单的函数,它在绕圈追着我。
如果我按如下方式运行它,我会得到一个内存泄漏:

function TtrackingsingleDlog.getJsonValue (const isScanDataB:boolean; scanNumberI: integer; pairnameS,fullStringS: string):string;
var
  jobject: TJSONObject;
  jobject2: TJSONObject;
  scansarray: TJSONArray;
  valueStringS:string;
begin
  valueStringS:='';
  jobject := TJSONObject.ParseJSONValue(fullStringS) as TJSONObject;
  if isScanDataB then
  begin
    jobject.TryGetValue('data', jobject2);
    if scanNumberI>=0 then
    begin
      if jobject2.TryGetValue('scans', scansarray) then
      begin
        scansarray[scanNumberI].TryGetValue<string>(pairnameS,valueStringS);
        jobject2.free;
      end;
    end
    else
    begin
      jobject2.TryGetValue(pairnameS, valueStringS);
      jobject2.free;
    end;
  end
  else
  begin
    jobject.TryGetValue(pairnameS, valueStringS);
    jobject.free;
  end;
  result:=valueStringS;
end;

如果我注解掉if scanNumberI>=0部分,并释放jobject,如下所示,泄漏就消失了:

function TtrackingsingleDlog.getJsonValue (const isScanDataB:boolean; scanNumberI: integer; pairnameS,fullStringS: string):string;
var
  jobject: TJSONObject;
  jobject2: TJSONObject;
  scansarray: TJSONArray;
  valueStringS:string;
begin
  valueStringS:='';
  jobject := TJSONObject.ParseJSONValue(fullStringS) as TJSONObject;
  if isScanDataB then
  begin
    jobject.TryGetValue('data', jobject2);
    {if scanNumberI>=0 then
    begin
      if jobject2.TryGetValue('scans', scansarray) then
      begin
        scansarray[scanNumberI].TryGetValue<string>(pairnameS,valueStringS);
        jobject2.free;
      end;
    end
    else
    begin
      jobject2.TryGetValue(pairnameS, valueStringS);
      jobject2.free;
    end; }
    jobject.free;
  end
  else
  begin
    jobject.TryGetValue(pairnameS, valueStringS);
    jobject.free;
  end;
  result:=valueStringS;
end;

但是,如果我把那部分放回去,jobject.free就会抛出一个访问冲突。
我肯定我在做蠢事,但就是不知道我错过了什么。

rmbxnbpk

rmbxnbpk1#

在您所展示的代码中,您负责释放的 * 唯一 * 对象是由ParseJSONValue()返回的对象(您应该使用try..finally来保护它!).
不要试图释放任何从JSON中提取的内部对象,因为它们默认由顶层JSON对象拥有,因此当您释放顶层对象时,它们将自动为您释放。
如果你想获得内部对象的所有权,你必须手动将它们的Owned属性设置为False
试试这个:

function TtrackingsingleDlog.getJsonValue (const isScanDataB: boolean; scanNumberI: integer; pairnameS, fullStringS: string): string;
var
  jvalue: TJSONValue;
  jobject: TJSONObject;
  jobject2: TJSONObject;
  scansarray: TJSONArray;
  valueStringS: string;
begin
  valueStringS := '';
  jvalue := TJSONObject.ParseJSONValue(fullStringS);
  if jvalue <> nil then
  try
    jobject := jvalue as TJSONObject;
    if isScanDataB then
    begin
      if jobject.TryGetValue('data', jobject2) then
      begin
        if scanNumberI >= 0 then
        begin
          if jobject2.TryGetValue('scans', scansarray) then
          begin
            scansarray[scanNumberI].TryGetValue<string>(pairnameS, valueStringS);
          end;
        end
        else
        begin
          jobject2.TryGetValue(pairnameS, valueStringS);
        end;
      end;
    end
    else
    begin
      jobject.TryGetValue(pairnameS, valueStringS);
    end;
  finally
    jvalue.Free;
  end;
  Result := valueStringS;
end;

相关问题