Memory allocation failed on sending Large byte[] using WCF in buffered mode

0

I want to use WCF for transfer file between clients and server. I read many article that some people using Stream mode for this purpose. but for it's restrictions I decide to create service with buffered mode. For example consider this:

[OperationContract]
void UploadFile(Guid systemKey, string fileName, byte[] fileContent, string userName);

server web config:

...
<system.web>
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" maxRequestLength="2147483647" executionTimeout="7200"/>
</system.web>
....
<bindings>
  <basicHttpBinding>
    <binding name="myBasicBinding" maxBufferSize="2147483647" 
                                   maxReceivedMessageSize="2147483647" 
                                   closeTimeout="01:50:00" 
                                   openTimeout="01:50:00" 
                                   sendTimeout="01:50:00" 
                                   receiveTimeout="01:50:00" 
                                   messageEncoding="Mtom">
      <readerQuotas maxDepth="128" maxStringContentLength="8388608" maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    </binding>
  </basicHttpBinding>
</bindings>
....
<system.webServer>
   <security>
      <requestFiltering>
           <requestLimits maxAllowedContentLength="4294967295"/>
      </requestFiltering>
   </security>
   <modules runAllManagedModulesForAllRequests="true"/>
   <directoryBrowse enabled="true"/>
</system.webServer>

and client config:

<system.web>
    <compilation debug="true" targetFramework="4.6"/>
    <httpRuntime targetFramework="4.6" maxRequestLength="2147483647" executionTimeout="7200"/>
</system.web>
...
<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="4294967295"/>
      </requestFiltering>
    </security>
</system.webServer>
<system.serviceModel>
    <bindings>
        <basicHttpBinding>
        <binding name="basicEndpoint"
                 maxBufferSize="2147483647"
                 maxReceivedMessageSize="2147483647"
                 closeTimeout="01:50:00"
                 openTimeout="01:50:00"
                 sendTimeout="01:50:00"
                 receiveTimeout="01:50:00"
                 messageEncoding="Mtom">
          <readerQuotas maxDepth="128" maxStringContentLength="8388608" maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
       </binding>
     </basicHttpBinding>
   </bindings>
   <client>
      <endpoint address="http://localhost/fts.svc" binding="basicHttpBinding" bindingConfiguration="basicEndpoint" contract="ServiceReference1.Ifts" name="basicEndpoint"/>
   </client>
</system.serviceModel>

I can upload 400MB file but when the size of file is 500MB or above I got this error:

System.InsufficientMemoryException HResult=0x8013153D Message=Failed to allocate a managed memory buffer of 1073741824 bytes. The amount of available memory may be low. Source=mscorlib

Inner Exception 1: OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. \

I think I set values for 2GB data but it fails on 500MB.

Thanks

this code run locally and I have 16GB RAM. Where is the problem and what value I should change to upload harge files?

Thanks

c#
wcf
wcf-binding
c#-7.0
.net-4.6
asked on Stack Overflow Jan 19, 2019 by Arian

2 Answers

2

I remember I was working with a large file transfer, and I used buffered mode to transfer but was not the best solution because after a while I got some exception about memory leak or something related memory, I changed it to transferMode="Streamed" and everything worked fine, by the buffered mode it means that the entire content of a message is present in memory before it is sent or after it is received. While that is a good strategy for most scenarios, and necessary for messaging features such as digital signatures and reliable delivery, large messages could exhaust a system's resources.
take a look at here.

To avoid creating new buffers all the time WCF uses BufferManager to reuse buffers, up to the limit specified by maxBufferPoolSize, buffers are expensive to create and destroy. You can use the BufferManager class to manage a buffer pool.

You can try increasing maxBufferPoolSize to see if you can reduce memory usage. I strongly recommend do not increase it to max because I think buffers from the pool are never released until the app-domain get recycles. A period of high traffic could cause a lot of memory to be used and never released.

So I recommend you to use streamed mode to transfer large file.

To split files and works with large streams below links may help you:

Multiple file in one Stream, custom stream
Best way to return large file as split zip files,Stream or Byte array WCF

it may also help you

Multiple stream in one stream will not passed to client properly

answered on Stack Overflow Jan 19, 2019 by Aria • edited Jan 19, 2019 by Aria
1

OutOfMemoryException says the process is using the maximum memory it is allowed to. Are you debugging the code whilst trying to upload this large file? Your IDE might be causing this problem. Moreover, in my opinion, when uploading large files the best approach is to split the file into smaller buffers and re-create them in the server side. Another approach can use FTP between the server and the client for handling the upload-download itself.

answered on Stack Overflow Jan 19, 2019 by Javi

User contributions licensed under CC BY-SA 3.0