How can I prevent BufferManager / PooledBufferManager in my WCF client app from wasting memory?

后端 未结 3 2287
Happy的楠姐
Happy的楠姐 2020-12-01 18:47

Analyzing a WCF client application (that I did not write and still do not know too much about) that talks to a bunch of services via SOAP and after running for a couple of d

相关标签:
3条回答
  • 2020-12-01 19:07

    I believe I have answer to your question #5:

    5) Or maybe even better, could we just tell all HttpsChannelFactory instances NOT to use BufferManagers at all and ask the GC to do its god-damn job, which is 'managing memory'?

    There is a MaxBufferPoolSize binding parameter, which controls max size of buffers in BufferManager. Setting it to 0 will disable buffering, and GCBufferManager will be created instead of pooled one - and it will GC allocated buffers as soon as message is processed, as in your question.

    This article discusses WCF memory buffer management in greater detail.

    0 讨论(0)
  • 2020-12-01 19:20

    As John says it would be easier to answer only one question instead of writing an essay. But here is what I think

    1) In a environment where we have GC, why would we need a BufferManager

    You seem to misunderstand the concept of GC and buffers. GC works with reference typed objects and frees memory if it detects that an object is a vertex (point or node) of a graph and it doesn't have any valid edges (lines or connections) to other vertices. Buffers are just some temporary storage for temporary array of raw data. For example, if you need to send a WCF application level message and its current size is larger than the transport level message size, WCF will do it in a few transport messages. On the receiver size, WCF will wait until the full application level message arrives and only then it would pass the message for processing (unless it's a streaming binding). The temporary transport messages are buffered - stored somewhere in memory on the receiver's end. As creating of new buffers for any new messages in this example can get very expansive, .NET provides you with a buffer management class that is responsible for pooling and sharing buffers.

    2) Despite of MS' claim that "This process is much faster than creating and destroying a buffer every time you need to use one.", shouldn't they leave that up to the GC (and its LOH for example) and optimize the GC instead?

    No they should not. Buffers and GC have nothing in common (unless you want to destroy the buffer every time, in the context of the sample, that is a design flaw). They have different responsibilities and address different problems.

    3) The app connects to a couple of different WCF services. For each of them we maintain a connection pool for the http connections

    HTTP binding is not design to handle large payload like 64Mb, consider changing the binding to more appropriate one. If you use the message of that sie, WCF will not pass it unless the whole 64Mb are fully received. Thus if you have 10 concurrent connections your buffer size will be 640Mb.

    For your other questions, please post another question on SO with some code and your WCF configuration. It will be easier to find where the problem is. Maybe the buffers aren't cleared because they are used inappropriately, you should consider the amount of testing that has been done on GC and WCF and the amount of testing that's been performed on a legacy project - follow the Occam's razor.

    0 讨论(0)
  • 2020-12-01 19:24

    4) Are we doing something wrong here? I'm not a WCF expert by any means, so could we make the various HttpsChannelFactory instances all use the same BufferManager?

    5) Or maybe even better, could we just tell all HttpsChannelFactory instances NOT to use BufferManagers at all and ask the GC to do its god-damn job, which is 'managing memory'?

    I guess one way of addressing those 2 questions could be changing the TransferMode from 'buffered' to 'streamed'. Will have to investigate, as 'streamed' mode has a couple of limitations and I might not be able to use it.

    Update: It actually works great! My memory consumption in buffered mode during startup of the app was 630M at peak times, and reduced to 470M when fully loaded. After switching to streamed mode, memory consumption does not show a temporary peak and when fully loaded, consumption is at only 270M!

    Btw., this was a one-line change in the client app code for me. I just had to add this line:

    httpsTransportBindingElement.TransferMode = TransferMode.StreamedResponse;
    
    0 讨论(0)
提交回复
热议问题