不正确的异常处理/对象释放可能导致内存泄漏(原因:未被注意到 "variable might not be assigned" 警告)

Improper exception handling / object freeing probably causes memory leak (Cause: unnoticed "variable might not be assigned" warning)

具有相同问题的示例的完整来源

Full source of example with same problem

继续使用单个 EXE 中的所有代码

我已将所有内容移动到单个 EXE

var SenderInstance: AutoGeneratedWebserviceUnit.Sender;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
  SenderInstance := AutoGeneratedWebserviceUnit.GetSender(False, 'http://invalid_URL');   // => there is no exception here
end;

...


procedure TForm1.Button1Click(Sender: TObject);
var
  req: AutoGeneratedWebserviceUnit.Request;
  res: AutoGeneratedWebserviceUnit.Response;
begin
  try
    req := Request.Create;
    try
      with req do
      begin
        ID := 0;
        param := 'trash';
      end;
      res := SenderInstance.Request('Login', 'Pass', req);   // => ESOAPHTTPException + EAccesViolation !
      ShowMessage(res.status);
    finally
      req.Free;
      res.Free;   // ### MOST POSSIBLE PROBLEM CAUSE ###
    end;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;

我理解 ESOAPHTTPException,但是 AV?为什么?...

问题

引发 ESOAPHTTPException 后发生奇怪的事情... 我想可能是内存泄漏之类的事情我无法弄清楚,或者我做了一些非常非常愚蠢的事情...

有什么设置吗?也许我忘记了什么?

线索

我发现了一些东西 关于 try/finally 块内的 "res.Free;" 行 禁用此行不会导致 AV 但是已分配(请求)returns 真 已分配(res) returns 也对...

什么……?

导致 AV 的问题在于 Button1Click 事件处理程序中的 try..finally 子句。

您正在尝试释放您的 res 变量(响应),自调用 Request 方法以来,该变量 尚未 分配任何内容失败并出现异常。这意味着它包含垃圾,并且通过调用 res.Free 您正在访问您不应该访问的内存位置,这几乎会引发任何类型的奇怪错误。

要解决这个问题,请在进入try..finally之前将res设置为nil,并在调用res.Free.

之前检查它是否已分配。

附带说明一下,这是因为 res 是一个 local 变量。如果它是 class 实例的 成员,编译器会自动为其分配一个 nil 值。

更新

正如@RobKennedy 所说,使用 nested try..finally 块比分配 nil 要好得多,就像我第一次告诉你的那样(这可能会导致如果某些析构函数失败会出现问题)。

所以你会做如下事情:

req := Request.Create;
try
  req.ID := 0;
  req.param := 'trash';

  res := SenderInstance.Request('Login', 'Pass', req); 
  try
    ShowMessage(res.status);
  finally
    res.Free;
  end;
finally
  req.Free;
end;