3

非常に大きな応答 (1 GB) で単一のサービス呼び出しを行う WCF クライアント アプリケーションがあります。このサービス コールを行うと大量のメモリ (500MB) が使用されることがわかりました。このメモリは、コードによって応答オブジェクトが参照されなくなっても、再利用されることはないようです。

メモリ プロファイラーを使用して、メモリ使用量の多くが PooledBufferManager インスタンスによって作成されたバイト配列にあることを確認しました。

私が使用しているプロキシ/クライアントは Visual Studio によって自動生成されているため、System.ServiceModel.ClientBase< TChannel > から派生したクラスです。

次の構成でカスタム バインディングを使用しています。

  <customBinding>
    <binding name="foo"
             closeTimeout="00:01:00"
             openTimeout="00:01:00"
             receiveTimeout="00:01:00"
             sendTimeout="00:01:00">
      <transactionFlow/>
      <reliableSession ordered="true" inactivityTimeout="00:02:00"/>
      <security authenticationMode="SecureConversation" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
        <secureConversationBootstrap messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
          <localClientSettings maxClockSkew="23:59:00"/>
        </secureConversationBootstrap>
        <localClientSettings maxClockSkew="23:59:00"/>
      </security>
      <mtomMessageEncoding>
        <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
      </mtomMessageEncoding>
      <httpTransport maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
    </binding>
  </customBinding>

人々の周りを読んで、これに対するいくつかの解決策について話しています。

  • バッファリングではなくストリーミング応答モードに切り替えますが、これはTCP WCF接続用であり、私のようなHTTP用ではないと思います.
  • maxBufferPoolSize をゼロに設定してバッファー プールを無効にします。これを httpTransport 要素に設定しても、私には何の効果もないようです。
  • 適切な BufferManager/PooledBufferManager で Clear() を呼び出します。私が持っている ClientBase 派生インスタンスのコンテキストから、これを呼び出すオブジェクトが見つかりません。デバッガーを使用して適切な PooledBufferManager インスタンスを見つけることができ、プライベートな innerChannelFactory フィールドを多くのレベルで深く掘り下げましたが、これはコードから操作するには役に立ちません。
  • GC.Collect() を手動で呼び出すと、未処理の 500MB のうち約 50MB が回収されるようです。

この 1 回限りのサービス コールで使用されたメモリをできるだけ多く再利用するには、どうすればよいでしょうか? この時点で、メモリを再利用するために強制終了できる専用プロセスでサービス呼び出しを行う寸前です。

4

1 に答える 1

2
  • バッファリングではなくストリーミング応答モードに切り替えますが、これはTCP WCF接続用であり、私のようなHTTP用ではないと思います.

http でも、実際にはhttpsの場合と同じようにストリーミング モードに切り替えることができますが、 httpでも同じように機能します

要素transferMode="Streamed"に属性を追加するだけです。httpTransportクライアントに関心があるため、クライアントの でこれを行う必要がありapp.configます。(サーバーをモードに変更する場合は、サーバーの web.config でも個別に行うことができstreamedます。ただし、クライアントとサーバーの両方を変更する必要はありません。転送モードは、ネットワーク上のバイトを変更しません)

  • maxBufferPoolSize をゼロに設定してバッファー プールを無効にします。これを httpTransport 要素に設定しても、私には何の効果もないようです。

これはまさにこの記事が主張するものです。

maxBufferPoolSize = 0 の場合は GCBufferManager が作成され、それ以外の場合は PooledBufferManager が作成されます。前者は些細なことであり、実際には何の管理も行いませんが、単にリクエストに対して新しいバッファを割り当て、ガベージ コレクタがそれを処理できるようにします。

つまり、GC.Collect()この場合、マニュアルで実際にうまくいく可能性があります。

  • 適切な BufferManager/PooledBufferManager で Clear() を呼び出します。私が持っている ClientBase 派生インスタンスのコンテキストから、これを呼び出すオブジェクトが見つかりません。

BufferManager インスタンスにもアクセスできませんでした。

  • GC.Collect() を手動で呼び出すと、未処理の 500MB のうち約 50MB が回収されるようです。

を呼び出さない限り、一度作成されたバッファは決して解放されないため、プールされたバッファマネージャでは機能しませClear()んが、インスタンスへのポインタが不足しています。

于 2014-04-08T05:22:32.767 に答える