4

我们使用 Bob Swart 的白皮书作为指南创建了一个 Datasnap 服务(使用 Delphi XE)。它工作正常,我们已将其部署到我们的测试服务器。

现在出现了一个问题,当我们执行了大量请求(通过 JMeter)时,会发生某种内存损坏。一些请求成功,一些因访问冲突而失败。最后,它变得如此腐败,以至于对我们的 OWN(而不是 DSAdmin)方法的每个请求都以访问冲突作为响应。

但是,我无法通过堆栈跟踪来获取更多信息,因为在处理请求时已经捕获了异常。

如果我使用此应用程序的 VCL 版本进行大量测试,它仍然可以正常工作。

有没有人知道这可能是什么,或者遇到了同样的问题,或者你能帮我从捕获的异常中获取堆栈跟踪(在别人的代码中,我无法编辑)?

提前致谢。

4

2 回答 2

7

要使用 JEDI JCL 记录已捕获和未捕获的异常,您应该安装JEDI JCL

然后尝试一些类似以下代码的代码jcl\examples\windows\debug\framestrack\FramesTrackDemoMain.pas

您应该在 delphi 项目选项中的 Compiler 和 Linker 选项中使用完整的调试信息进行编译,这样才能正常工作。

请注意,您不必调用 LogException,它会在您添加异常通知回调 (JclAddExceptNotifier) 时自动调用。不要忘记调用 JclRemoveExceptNotifier,当您从中添加它的表单或数据模块被销毁时,如下所示:

procedure TForm1.LogException(ExceptObj: TObject; ExceptAddr: Pointer; IsOS: Boolean);
var
  TmpS: string;
  ModInfo: TJclLocationInfo;
  I: Integer;
  ExceptionHandled: Boolean;
  HandlerLocation: Pointer;
  ExceptFrame: TJclExceptFrame;

begin
  TmpS := 'Exception ' + ExceptObj.ClassName;
  if ExceptObj is Exception then
    TmpS := TmpS + ': ' + Exception(ExceptObj).Message;
  if IsOS then
    TmpS := TmpS + ' (OS Exception)';
  mmLog.Lines.Add(TmpS);
  ModInfo := GetLocationInfo(ExceptAddr);
  mmLog.Lines.Add(Format(
    '  Exception occured at $%p (Module "%s", Procedure "%s", Unit "%s", Line %d)',
    [ModInfo.Address,
     ModInfo.UnitName,
     ModInfo.ProcedureName,
     ModInfo.SourceName,
     ModInfo.LineNumber]));
  if stExceptFrame in JclStackTrackingOptions then
  begin
    mmLog.Lines.Add('  Except frame-dump:');
    I := 0;
    ExceptionHandled := False;
    while (chkShowAllFrames.Checked or not ExceptionHandled) and
      (I < JclLastExceptFrameList.Count) do
    begin
      ExceptFrame := JclLastExceptFrameList.Items[I];
      ExceptionHandled := ExceptFrame.HandlerInfo(ExceptObj, HandlerLocation);
      if (ExceptFrame.FrameKind = efkFinally) or
          (ExceptFrame.FrameKind = efkUnknown) or
          not ExceptionHandled then
        HandlerLocation := ExceptFrame.CodeLocation;
      ModInfo := GetLocationInfo(HandlerLocation);
      TmpS := Format(
        '    Frame at $%p (type: %s',
        [ExceptFrame.ExcFrame,
         GetEnumName(TypeInfo(TExceptFrameKind), Ord(ExceptFrame.FrameKind))]);
      if ExceptionHandled then
        TmpS := TmpS + ', handles exception)'
      else
        TmpS := TmpS + ')';
      mmLog.Lines.Add(TmpS);
      if ExceptionHandled then
        mmLog.Lines.Add(Format(
          '      Handler at $%p',
          [HandlerLocation]))
      else
        mmLog.Lines.Add(Format(
          '      Code at $%p',
          [HandlerLocation]));
      mmLog.Lines.Add(Format(
        '      Module "%s", Procedure "%s", Unit "%s", Line %d',
        [ModInfo.UnitName,
         ModInfo.ProcedureName,
         ModInfo.SourceName,
         ModInfo.LineNumber]));
      Inc(I);
    end;
  end;
  mmLog.Lines.Add('');
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  JclAddExceptNotifier(Form1.LogException);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  JclRemoveExceptNotifier(Form1.LogException);
end;

这是通常的初始化代码:

initialization

  JclStackTrackingOptions := JclStackTrackingOptions + [stExceptFrame];
  JclStartExceptionTracking;

这是运行的 JCL FramesTrackExample.dproj 演示:

在此处输入图像描述

出于您的目的,将向 TMemo.Lines 添加一行的代码更改为写入磁盘上的日志文件。如果你已经有一个日志系统,那就太好了,如果没有,那么考虑Log4D

于 2011-12-16T21:23:01.707 回答
-1

每个新的 Web 服务调用都是一个新线程。当下一个服务调用到来并且新线程尝试访问它们时,前一个线程可以分配一些资源。或者当另一个线程试图使用它们时,一个线程可能会释放一些资源。您应该使用 TCriticalSection 确保所有资源仅可用于一个线程。还要确保 TCriticalSection 是一个全局变量并且可以被所有实例访问。

于 2011-12-19T19:49:51.253 回答