【问题标题】:Access violation when i try free TJSONObject当我尝试免费的 TJSONObject 时访问冲突
【发布时间】:2020-07-24 02:47:48
【问题描述】:

我有下面的代码,但是当我尝试释放变量 checkID 时,我得到一个访问冲突错误,如果我不销毁它,我会遇到内存泄漏问题。

function TdtmData.CheckID(AID: String): Boolean;
var
  checkID : TJSONObject;
  clientModule : TcmClientModule;
  ok : Boolean;
begin
  Result := False;
  try
    try
      clientModule := TcmClientModule.Create(Self);
      checkID := clientModule.smMethodsServerClient.CheckID(AID);
      ok := checkID.GetValue<Boolean>('Register', False);
      if not(ok) then
        raise Exception.Create('ID ERROR.');
    finally
      clientModule.DisposeOf;
      checkID.Free; // <-- The error is here (Access violation)
    end;
    Result := ok;
  except
    on e : Exception do
      raise Exception.Create(e.Message);
  end;

end;

smMethodsServerClient.CheckID(AID) 方法是通过 TDSRestConnection 组件自动创建的。

function TsmMethodsServerClient.CheckID(AID: string; const ARequestFilter: string): TJSONObject;
begin
  if FCheckIDCommand = nil then
  begin
    FCheckIDCommand  := FConnection.CreateCommand;
    FCheckIDCommand.RequestType := 'GET';
    FCheckIDCommand.Text := 'TsmMethodsServer.CheckID';
    FCheckIDCommand.Prepare(TsmMethodsServer_CheckID);
  end;
  FCheckIDCommand.Parameters[0].Value.SetWideString(AIDPDV);
  FCheckIDCommand.Execute(ARequestFilter);
  Result := TJSONObject(FCheckIDCommand.Parameters[1].Value.GetJSONValue(FInstanceOwner));
end;

我还使用 Datasnap REST 客户端模块向导创建了我的类 TcmClientModule。

【问题讨论】:

  • 将变量 (checkID) 命名为与函数 (CheckID) 完全相同的名称是一个非常糟糕的主意。 Delphi 不区分大小写,旧式 Pascal 使用 functionname := returnvalue 而不是(现在)内置的 Result 从函数返回值。
  • TcmClientModule.Create() 的调用应该在try 块之上。并且应该有第二个try..finally 来释放TJSONObject,假设它应该从一开始就被释放。 csmMethodsServerClient.CheckID() 长什么样子?
  • 如果 clientModule := TcmClientModule.Create(Self);checkID := clientModule.smMethodsServerClient.CheckID(AID); 失败并出现异常, FINALLY 块在没有初始化 checkID 的情况下执行(参见上面 Remy 的评论),当您尝试释放未初始化的对象时,这很可能会导致访问冲突。这就是为什么您应该始终将受保护对象的分配/初始化放置在 TRY/FINALLY 块之外。
  • 这是一种 DataSnap 应用程序吗?
  • 这是一个datasnpat应用程序。

标签: delphi delphi-xe8 datasnap


【解决方案1】:

作为DataSnap参数的JSONValue不需要是Free。

另外,如果释放参数对象的内存,释放DataSnap DataModule或第二次调用该参数所在的接口时可能会出错。

即使每次使用DataSnap接口都新建一个JSONValue参数,也不存在内存泄漏等问题。

此外,不应进一步释放因 DataSnap 接口接收的 JSONValue 对象。

================================================ ==

clientModule.DisposeOf;

这会为 checkID 释放内存。但是,“checkID := nil”没有设置。下面的条件语句会一直执行,执行时会出错。

if Assigned(checkId) then 
  checkID.Free;

【讨论】:

  • 在这种情况下,MadExcept 显示的内存泄漏可以忽略吗?
  • @DeivisÁtila 是的。你可以忽略它。其实如果你自己做压力测试,你可以看到内存并没有增加。
【解决方案2】:

也许当你在做这件事的时候

clientModule.DisposeOf;

checkID 将被销毁,因为checkIDclientModule 的一部分,因为这部分代码

clientModule.smMethodsServerClient.CheckID(AID);

您可以先尝试清除checkID,然后再清除clientModule

更新:另一种避免错误的方法是在销毁之前检查checkId。 或许这种方式比较合适:

if Assigned(checkId) then 
  checkID.Free;

也许除了这个检查你还需要检查null 的对象。

【讨论】:

  • 我尝试先免费,也出现错误。
  • @DeivisÁtila 我更新了我的答案,也许这会对你有所帮助
  • 错误仍在继续,我正在考虑停止使用向导并创建自己的类来发出请求。谢谢。
  • @DeivisÁtila 一点也不。很遗憾你不能解决你的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多