2011-12-15 104 views
4

我們使用Bob Swart的白皮書作爲指南創建了Datasnap服務(使用Delphi XE)。它工作正常,我們已經將它部署到我們的測試服務器。如何從處理/捕獲的異常中獲取堆棧跟蹤並將其轉儲到跟蹤日誌中

現在出現問題,當我們執行了大量請求(通過JMeter)時,會發生某種內存損壞。有些請求成功,有些請求會違反訪問權限。最後,它變得如此腐敗,以至於我們對OWN(而不是DSAdmin)方法的每個請求都會以訪問衝突做出響應。

但是,我無法抓住堆棧跟蹤來獲取更多信息,因爲在處理請求時已經捕獲到異常。

如果我用此應用程序的VCL版本進行大量測試,它仍然正常工作。

有沒有人知道這可能是什麼,或者遇到過同樣的問題,或者你能幫我從捕獲到的異常中獲取堆棧跟蹤(在別人的代碼中,我無法編輯)?

在此先感謝。

+1

您可以添加異常處理程序(如[MadExcept](http://madshi.net/madExceptDescription.htm)或我們的[開源單元](http://blog.synopse.info/post/2011/04)/14/Enhanced-logging-in-SynCommons))在運行期間檢索堆棧跟蹤。如果沒有這個堆棧跟蹤,找到根本原因是不可能的。添加日誌記錄將有助於調試服務。 – 2011-12-15 16:42:45

+2

是的,您可以在捕捉到的異常情況下登錄堆棧軌道。從JEDI類庫獲取JclDebug,並將其添加到您的應用程序。如果您將問題編輯爲「如何從處理/捕獲的異常中獲取堆棧跟蹤並將其轉儲到跟蹤日誌」,我將很樂意發佈諸如答案。我曾多次使用該技術(跟蹤日誌+ JCL調試)來調試服務崩潰。 – 2011-12-15 17:18:08

+0

聽起來就像你遇到了競爭條件。 你想過線程安全嗎? – whosrdaddy 2011-12-15 19:25:59

回答

7

要使用JEDI JCL記錄捕獲和未捕獲的異常,應該安裝JEDI JCL

然後嘗試一些代碼,就像從jcl\examples\windows\debug\framestrack\FramesTrackDemoMain.pas採取了這種代碼:

你應該在編譯器,並在您的Delphi工程的選項鍊接器選項都完整的調試信息編譯,對於這個工作。

請注意,您不必調用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演示運行:

enter image description here

你的目的,修改,增加了一行TMemo.Lines的代碼,改爲寫入磁盤上的日誌文件。如果你已經有一個日誌系統,那很好,如果沒有,那麼考慮Log4D

-1

每個新的Web服務調用都是一個新線程。當下一個服務調用即將到來並且新線程嘗試訪問它們時,可以通過前一個線程分配一些資源。或者當另一個線程嘗試使用它們時,某個線程可能會釋放一些資源。您應該使用TCriticalSection來確保所有資源僅適用於一個線程。還要確保TCriticalSection是一個全局變量,並且可以被所有實例訪問。