不正确的异常处理/对象释放可能会导致内存泄漏(原因:未注意到"变量可能未分配"警告)

时间:2015-02-12 09:02:21

标签: web-services delphi dll memory-leaks

具有相同问题的完整示例

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后会发生奇怪的事情...... 我认为有一些类似于内存泄漏的东西,我无法弄清楚,或者我做了一些非常愚蠢的事情......

任何设置?也许我忘记了什么?

线索

我找到了一些东西 关于" res.Free;"在try / finally块里面的行 禁用此行不会导致AV 但Assigned(req)返回True Assigned(res)也返回True ...

什么......?

1 个答案:

答案 0 :(得分:2)

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

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

要解决此问题,请在输入nil之前将res设置为try..finally,并在致电res.Free之前检查是否已分配。

另一方面,这是因为res本地变量。如果它是类的实例的成员,编译器会自动为其分配nil值。

<强>更新

正如@RobKennedy所说,使用嵌套 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;