2012-01-19 4 views
4

オブジェクトで、時には明示的gc.collect呼び出す必要があります機能しますあなたはCOMがここ

 Private Sub LoadEmail() 

     Dim loSession As RDOSession = Nothing 
     Dim loMessages As RDOItems = Nothing 

     Try 
      moNDRs = New List(Of NonDeliveryRecord) 
      loSession = New Redemption.RDOSession 
      loSession.LogonExchangeMailbox(MailAccountName, MailServerName) 
      loMessages = loSession.GetDefaultFolder(rdoDefaultFolders.olFolderInbox).Items 
      Dim Counter = 0 
      For Each loMessage As RDOMail In loMessages 
       Counter += 1 
       moNDRs.Add(CreateNDRRecord(loMessage)) 
       Marshal.ReleaseComObject(loMessage) 
       loMessage = Nothing 
       If Counter Mod 100 = 0 Then GC.Collect() 
      Next 


     Finally 
      If loSession IsNot Nothing Then 
       loSession.Logoff() 
       Marshal.FinalReleaseComObject(loSession) 
       loSession = Nothing 
      End If 

      If loMessages IsNot Nothing Then 
       Marshal.FinalReleaseComObject(loMessages) 
       loMessages = Nothing 
      End If 

     End Try 

    End Sub 

メッセージクラスは、上記の使用Redemptionです。あなたは上記の機能を見ると、あなたが表示されます。私たちが抱えている問題を解決するためにしなければならなかったものです

If Counter Mod 100 = 0 Then GC.Collect() 

。私は今朝(ANT & dottrace)メモリープロファイラーで遊んでいましたが、何かを見いだすことができるかどうかを見ていますが、これまでのところすべてがうまく見えます。私は低レベルではありません誰がwindgbのインとアウトを知っているでしょう。

私は取得していますエラーは次のとおりです。IMAPISession :: OpenEntryで エラー:MAPI_E_TOO_BIG

私は常にエラーが次のコードにコメントされますライン。私は〜450の反復の後でいつもエラーを得る。

これは、gc.collectを使用しなければならない数のうちの1つで、COMオブジェクトを扱うときですか?

はここでエラーがで発生したラインとCreateNDR機能である:

 Public Function CreateNDRRecord(ByVal voMessage As RDOMail) As NonDeliveryRecord 

     Dim loItem As RDOReportItem = Nothing 
     Dim loMatches As MatchCollection = Nothing 
     Dim loNonDeliveryCode As NonDeliveryRecord = New NonDeliveryRecord 
     Dim lsMessage As String = String.Empty 


     Try 
      loNonDeliveryCode.IsBadMessage = False 
      loNonDeliveryCode.MailMessageId = voMessage.EntryID 

      'Debug.Print(voMessage.MessageClass.Equals("REPORT.IPM.Note.NDR").ToString()) 
      If voMessage.MessageClass.Equals("REPORT.IPM.Note.NDR") Then 'error always happens here 
       loItem = CType(voMessage, RDOReportItem) 
       If voMessage.Recipients.Count <> 0 Then 
        loNonDeliveryCode.EmailAddress = voMessage.Recipients(1).Name 
       End If 
       loNonDeliveryCode.IsUndeliverable = True 
       lsMessage = loItem.ReportText 

      ElseIf voMessage.Subject.Contains(mconSeparator) Then 
       loNonDeliveryCode.EmailAddress = voMessage.Subject.Substring(voMessage.Subject.LastIndexOf(mconSeparator) + mconSeparator.Length) 
       loNonDeliveryCode.ErrorCode = String.Empty 
       loNonDeliveryCode.IsUndeliverable = True 
       lsMessage = voMessage.Body 
      End If 

      If loNonDeliveryCode.IsUndeliverable Then 

       loMatches = GetErrorType(lsMessage) 

       If loMatches.Count > 0 Then 
        loNonDeliveryCode.ErrorCode = loMatches(loMatches.Count - 1).Value 
       End If 

       Dim loNDRId = GetErrorCode(loNonDeliveryCode.ErrorCode) 

       If loNDRId.Count > 0 Then 
        loNonDeliveryCode.ErrorCodeId = CType(CType(loNDRId(0), DataRow).Item("NonDeliveryCodeId"), Integer) 
        loNonDeliveryCode.ErrorDescription = CType(CType(loNDRId(0), DataRow).Item("Description"), String) 
        loNonDeliveryCode.MarkAsInvalid = CType(CType(loNDRId(0), DataRow).Item("MarkAsInvalid"), Boolean) 
       Else 
        If voMessage.MessageClass.Equals("REPORT.IPM.Note.NDR") Then 
         loNonDeliveryCode.ErrorCode = String.Empty 
         loNDRId = GetErrorCode(loNonDeliveryCode.ErrorCode) 
         loNonDeliveryCode.ErrorCodeId = CType(CType(loNDRId(0), DataRow).Item("NonDeliveryCodeId"), Integer) 
         loNonDeliveryCode.ErrorDescription = CType(CType(loNDRId(0), DataRow).Item("Description"), String) 
         loNonDeliveryCode.MarkAsInvalid = CType(CType(loNDRId(0), DataRow).Item("MarkAsInvalid"), Boolean) 
        Else 
         loNonDeliveryCode.ErrorCode = String.Empty 
         loNonDeliveryCode.ErrorCodeId = 1 
        End If 
       End If 

      End If 


      Return loNonDeliveryCode 

     Catch Ex As Exception 
      loNonDeliveryCode.IsUndeliverable = False 
      loNonDeliveryCode.IsBadMessage = True 
      Return loNonDeliveryCode 

     Finally 
      If loItem IsNot Nothing Then 
       Marshal.FinalReleaseComObject(loItem) 
       loItem = Nothing 
      End If 

      If voMessage IsNot Nothing Then Marshal.ReleaseComObject(voMessage) 

      If loMatches IsNot Nothing Then 
       loMatches = Nothing 
      End If 

     End Try 

答えて

5

は、プログラムだけでリソースをクリーンアップするために十分なファイナライザスレッドを起動するのに十分なガベージコレクションのメモリを消費しない場合があります。トラブルメーカは、例えばThreadクラスです。 5つのオペレーティングシステムハンドルを消費しますが、早期に解放するDispose()メソッドはありません。そしてあなたが使用しているもののようなCOMコクラスは、CLRが作成するマネージラッパーはファイナライザを持っていますが、IDisposableを実装していません。ユーザプログラムが効果的または確実にDispose()を呼び出せないクラスの例。

GC.Collect()がこのような場合に作成されました。また、GC.WaitForPendingFinalizers()を呼び出すと、それは実際に起こりたいことです。

あなたの使い方は間違いありません。あなたはそれを調整する必要があります。

+0

ありがとうございます。私が気付いたことの一つは、perfmonを使用していたときに、GCハンドルが大量にリリースされていたことです。 – coding4fun

+0

'Thread'は、開始された後にのみ、または何らかの目的で必要になったときに遅延してハンドルを熱心に作成しますか? – supercat

4

実行中のCOMオブジェクトの実際のメモリフットプリントを理解していない管理されたヒープが関係している可能性があります。

.NETランタイムの観点から、あなたのCOMオブジェクトは、小さなある自動作成ランタイム呼び出し可能ラッパー(RCW)のフットプリントを持っています。膨大な量のメモリを保持するCOMオブジェクトをインスタンス化している可能性がありますが、そのメモリは.NETメモリヒープには存在しないため、ガベージコレクタはそれをクリーンアップする必要はありません。

このような状況でガベージコレクタを強制的に実行することは、正しいことと思われます。参照されていないRCWはすべて破棄され、COM参照カウントがCOMオブジェクトにドロップされ、解放されます(もちろん、そのオブジェクトへの他のCOM参照がないと仮定します)。

関連する問題