2016-05-26 14 views
0

私は、WCFクライアントを使用してJava Webサービスと通信するアプリケーションを持っています。サービスの一つが適度に大きな結果(約100 MB)を返し、時には我々は、OutOfMemoryException例外を取得:OutOfMemoryException WebServicesからデータを受信する

System.IO.MemoryStream.set_Capacity(Int32)を
System.IO.MemoryStream.EnsureCapacity(Int32)を
System.IO.MemoryStream.Write(バイト[]、Int32、Int32)をオーバーライドします
System.Xml.XmlMtomReader + MimePart.GetBuffer(のInt32、のInt32のByRef)
System.Xml.XmlMtomReader.Initialize(System.IO.Stream、 System.String、 System.Xml.XmlDictionaryReaderQuotas、Int32)
System.Xml.XmlMtomReader.SetInput(System.IO.Stream、 System.Text.Encoding []、可能System.String、 System.Xml.XmlDictionaryReaderQuotas、のInt32、 System.Xml.OnXmlDictionaryReaderClose)
System.ServiceModel.Channels.MtomMessageEncoder.TakeStreamedReader(System.IO.Stream、 システム。ストリング)
System.ServiceModel.Channels.MtomMessageEncoder.ReadMessage(System.IO.Stream、 のInt32、可能System.String)
System.ServiceModel.Channels.HttpInput.ReadStreamedMessage(System.IO.Stream) System.ServiceModel。 Channels.HttpInput.ParseIncomingMessage(System.Exception ByRef)
System.ServiceModel.Channels.HttpChannelFactory + Ht tpRequestChannel + HttpChannelRequest.WaitForReply(のSystem.TimeSpan) System.ServiceModel.Channels.RequestChannel.Request(System.ServiceModel.Channels.Message、 のSystem.TimeSpan)
System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel。 Channels.Message、 のSystem.TimeSpan)
System.ServiceModel.Channels.ServiceChannel.Call(可能System.String、 ブール、System.ServiceModel.Dispatcher.ProxyOperationRuntime、 System.Objectの[]、System.Objectの[]、システム.TimeSpan)
System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage、 System.ServiceModel.Dispatcher.ProxyOperat ionRuntime)
System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage) System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData のByRef、のInt32 600メガバイトと応答がaroungです - アプリケーションは約400を消費する32ビットアプリケーションであるとしてデータの)

当社のWCFクライアント....

量は、実際のOutOfMemoryExceptionを作成するのに十分な大きさではありません何か他のことが起こっているはずです。

+2

あなたは100MBの容量のチャンクを頻繁に受信し、アプリケーションは32ビット(なぜですか?)の場合、メモリが断片化する可能性があるため、100MBの連続したメモリがありません。 – Evk

+0

ここでこれについての良い記事です:https://blogs.msdn.microsoft.com/ericlippert/2009/06/08/out-of-memory-does-not-refer-to-physical-memory/ – Evk

+0

フラグメンテーションはここでは無関係です。現在のオペレーティングシステムはすべて、ページングされた仮想メモリを使用していました。断片化は、連続した割り当てで発生します。 – AhmadWabbi

答えて

1

そのような行動につながる物事のカップルがあります:

  1. 32ビットプロセスは、それだけの2ギガバイト(時には3ギガバイト)は仮想アドレス空間(1〜2ギガバイトが予約されている、としてのアドレスができ32-あなたは4GBをアドレス指定することができます)。

  2. 。NETは、特別なラージオブジェクトヒープ上に大きなオブジェクト(85000バイトより大きい)を格納します。このヒープはデフォルトでが圧縮されていません。(および.NET 4.5.1より前のバージョンでは圧縮されません)。 40MB、次に10MB、そして70MBのメモリを割り当てたとします。しばらくすると、40MBと70M​​Bがガベージコレクションされました。 100MBのチャンクを割り当てたいとします。ラージオブジェクトヒープが圧縮されている場合は、少なくとも110MBの連続した空きアドレス空間を持つことができます。しかし、そうではないので、40MBと70M​​Bという2つのギャップがあります。このため、100MBのチャンクを割り当てることはできません。

は、そのマシン上の空き物理RAMがたくさんあるので、あっても(でもない場合や - が常にスワップ)、あなたは十分な大きさのアドレス空間の連続チャンクへのポインタを取得することができない場合があります。この場合、OutOfMemoryExceptionがスローされます。これを解決する方法の

カップル:

  1. 64ビットプロセスを使用してください。
  2. バイト配列を再利用してメモリチャンクを再利用します。たとえば、WCFはBufferManagerを提供(使用)します。
  3. .NET 4.5.1では、ラージオブジェクトヒープをコンパクトにする方法が提供されていますが、実際に問題を解決するわけではありません。遅らせるだけです。あなたは行って、(あなたはすべてのコレクションに圧縮することを強制することはできません)一度LOHを圧縮することができます

    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; 
    GC.Collect();  
    
+0

WCFクライアントをバッファリングからストリーミングに移行するにはどうすればよいですか? 1)に関しては、プロセスが600Mbしか消費していないので、ここでは問題ではありません。 –

+0

はい、ストリーミングに移行するとそれも役に立ちます。 32ビットプロセスでは、これは確かに問題です。ここで問題となるのは、十分な大きさの_addressスペースを割り当てることができないからです。 32bitプロセスでは、私が記述したようにアドレス空間はわずか2GBです。 64ビットプロセスでは数テラバイトです。どのような物理メモリが存在していても、アプリケーションが現在どのくらいのメモリを消費しているかは何ら関係ありません(言及した600MBのもの)。 – Evk

0

WCF WebServiceHostを使用して、バッファまたはメッセージのサイズを制限しないように設定を設定してみてください:

using System; 
    using System.ServiceModel.Web; 

    private WebServiceHost webHost; 

    public void Start() 
    { 
     webHost.Opening += ConfigureEnpointBinding; 

     webHost.Open(); 
    } 

    private void ConfigureEnpointBinding(object sender, EventArgs e) 
    { 
     var endpointBinding = (System.ServiceModel.WebHttpBinding) 
      ((WebServiceHost)sender) 
      .Description 
      .Endpoints 
      .Single(endpoint => endpoint.Contract.ContractType == typeof(IYourInterface)) 
      .Binding; 

     endpointBinding.MaxReceivedMessageSize = int.MaxValue; 
     endpointBinding.MaxBufferSize = int.MaxValue; 
    } 
関連する問題