You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi应用陷入Access Violation无限循环,如何用madExcept捕获追踪?

Delphi应用概率性Access Violation无限循环异常排查

问题现象

  • 应用概率性出现停滞,陷入Access Violation异常无限循环,异常对话框反复弹出
  • 开启madExcept编译后,Bug报告进度对话框反复弹出,无法查看单份报告
  • 异常在DataGridHotTrackNode事件中触发,前10-20秒代码运行正常

已尝试的madExcept配置(无效)

  • 勾选「异常自动操作-各类操作-自动保存Bug报告(仅当报告未发送时)」
  • 勾选「异常自动操作-应用控制-自动继续应用」
  • 未找到自动保存的Bug报告,应用仍持续运行并触发异常循环

相关触发代码

procedure TInvoiceForm.DataGridHotTrackNode(Sender: TObject;
  AHotTrackInfo: TdxTreeListHotTrackInfo; var ACursor: TCursor);
var
  HitInfo: TdxTreeListHitInfo;
  GridPoint: TPoint;
  AColumn: TdxDBTreeListColumn;
  ARow: Integer;
  Tmp: String;
begin
  if IsPopupShowing then Exit;
  IsPopupShowing := True;
  try
    GridPoint := DataGrid.ScreenToClient(Mouse.CursorPos);

    HitInfo:=DataGrid.GetHitInfo(GridPoint);

    if ( (HitInfo.hitType = htColumn) or (HitInfo.hitType = htLabel) ) then begin
      if Assigned(HitInfo.Node) then
        if {Assigned(HitInfo.Node.Values[HitInfo.Column])} (1=1) then begin
          try
            if HitInfo.Column<HitInfo.Node.CountValues then
              if not VarIsNull(HitInfo.Node.Values[HitInfo.Column]) then
                Tmp:=HitInfo.Node.Values[HitInfo.Column]
              else
                Tmp:=''
            else
              Tmp:='';
          except
            on E: Exception do begin
              Tmp:='';
            end;
          end;

          if PopupForm <> nil then
            FreeAndNil(PopupForm);

          PopupForm := TForm.Create(nil);
          try
            // Configure PopupForm based on the Node information
            // ...

            if Assigned(PopupForm) then
            PopupForm.Caption:=Tmp;

            if Assigned(PopupForm) then
            PopupForm.Position := poDesigned;

            if Assigned(PopupForm) then
            PopupForm.Left := Mouse.CursorPos.X; // Adjust as needed

            if Assigned(PopupForm) then
            PopupForm.Top := Mouse.CursorPos.Y;  // Adjust as needed

            if Assigned(PopupForm) then
            PopupForm.Show;
          except
            FreeAndNil(PopupForm);
          end;
        end;
    end else begin
      if Assigned(PopupForm) then
        FreeAndNil(PopupForm);
    end;
  finally
    IsPopupShowing := False; 
  end;
end;

注:正在为TdxDBGrid单元格开发自动弹出/关闭的窗口,已添加单线程并发防护

解决方案建议

一、madExcept配置优化

  • 强制保存Bug报告:
    1. 打开madExcept设置,进入「异常自动操作」→「各类操作」,勾选「自动保存Bug报告(总是保存,不管是否发送)」
    2. 手动指定绝对保存路径(如C:\BugReports\),确保程序拥有该路径的读写权限
    3. 取消「自动继续应用」,改为勾选「自动终止应用(仅当报告已保存时)」,避免异常循环触发
  • 屏蔽重复异常弹窗:
    进入「异常处理」→「高级」,勾选「忽略重复的异常(短时间内同一位置触发的相同异常)」,设置500ms左右的阈值
  • 启用静默异常处理:
    在程序启动代码中添加自定义异常处理,直接保存报告不弹窗:
    procedure SaveExceptionSilently(const exceptIntf: IMEException; var handled: Boolean);
    begin
      exceptIntf.SaveBugReportToFile('C:\BugReports\report_' + DateTimeToStr(Now) + '.zip');
      handled := True;
    end;
    
    // 在FormCreate或项目初始化中注册
    madExcept.RegisterExceptionHandler(SaveExceptionSilently, stDontSync);
    

二、代码风险点修复

  1. 优化PopupForm生命周期:
    避免反复创建销毁非模态窗口,改用全局实例复用:
    // 全局变量改为:PopupForm: TForm = nil;
    if not Assigned(PopupForm) then
      PopupForm := TForm.Create(nil);
    // 配置PopupForm...
    PopupForm.Show;
    // 需要关闭时再FreeAndNil(PopupForm)
    
  2. 增强HitInfo有效性校验:
    添加HitInfo.Column的空值检查,避免无效索引访问:
    if Assigned(HitInfo.Node) and Assigned(HitInfo.Column) then
    begin
      if HitInfo.Column.Index < HitInfo.Node.CountValues then
        // 访问Values逻辑
    end;
    
  3. 强化竞态防护:
    用TCriticalSection保护IsPopupShowing变量,避免事件重入触发:
    // 声明全局临界区:FCriticalSection: TCriticalSection;
    // 初始化:FCriticalSection := TCriticalSection.Create;
    // 销毁:FCriticalSection.Free;
    FCriticalSection.Enter;
    try
      if IsPopupShowing then Exit;
      IsPopupShowing := True;
    finally
      FCriticalSection.Leave;
    end;
    
  4. 缓存鼠标坐标:
    在事件开头缓存坐标,避免后续处理中坐标变化导致的异常:
    GridPoint := DataGrid.ScreenToClient(Mouse.CursorPos);
    const MousePos = Mouse.CursorPos; // 缓存坐标
    // 后续设置PopupForm位置时用MousePos
    PopupForm.Left := MousePos.X;
    PopupForm.Top := MousePos.Y;
    

三、其他排查手段

  • WinDbg附加分析:当异常循环时,用WinDbg附加到进程,执行!analyze -v获取详细异常调用栈,定位具体出错代码行
  • 添加日志追踪:在事件关键节点(创建PopupForm、访问Node.Values、释放窗口)添加日志,记录时间、变量值,回溯异常触发前状态
  • 临时禁用事件:注释掉DataGridHotTrackNode事件绑定,确认异常是否消失,验证是否为该事件导致

内容的提问来源于stack exchange,提问作者TomR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 17:01:23