Не удалось выделить память при отправке Large byte [] с использованием WCF в режиме буферизации - PullRequest
0 голосов
/ 19 января 2019

Я хочу использовать WCF для передачи файлов между клиентами и сервером. Я прочитал много статей, что некоторые люди используют режим Stream для этой цели. но из-за его ограничений я решил создать сервис с буферным режимом. Например, рассмотрим это:

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

веб-конфигурация сервера:

...
<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>

и клиентская конфигурация:

<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>

Я могу загрузить 400MB файл, но когда размер файла 500MB или выше, я получил эту ошибку:

System.InsufficientMemoryException HResult = 0x8013153D Сообщение = не удалось выделить буфер управляемой памяти размером 1073741824 байта. Объем доступной памяти может быть низким. Источник = mscorlib

Внутреннее исключение 1: OutOfMemoryException: было сгенерировано исключение типа System.OutOfMemoryException. \

Я думаю, я установил значения для 2GB данных, но он не работает на 500MB.

Спасибо

этот код запускается локально, и у меня 16GB RAM. В чем проблема и какое значение я должен изменить, чтобы загружать файлы harge?

Спасибо

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Я помню, я работал с передачей больших файлов, и я использовал режим buffered для передачи, но это было не лучшее решение, потому что через некоторое время я получил какое-то исключение из-за утечки памяти или чего-то связанного с памятью, я изменил его на transferMode="Streamed" и все работало нормально, в режиме buffered это означает, что все содержимое сообщения присутствует в памяти до его отправки или после его получения.Хотя это хорошая стратегия для большинства сценариев и необходима для таких функций обмена сообщениями, как цифровые подписи и надежная доставка, большие сообщения могут исчерпать ресурсы системы.
посмотрите на здесь .

Чтобы не создавать новые буферы постоянно, WCF использует BufferManager для повторного использования буферов, вплоть до ограничения, указанного в maxBufferPoolSize, buffers дорого создавать и уничтожать.Вы можете использовать BufferManager класс для управления буферным пулом.

Вы можете попробовать увеличить maxBufferPoolSize, чтобы посмотреть, сможете ли вы уменьшить использование памяти.Я настоятельно рекомендую не увеличивать его до максимума, потому что я думаю, что буферы из пула никогда не освобождаются до тех пор, пока домен приложения не перезапустится.Период большого трафика может привести к тому, что будет использовано много памяти и она никогда не будет освобождена.

Поэтому я рекомендую использовать режим streamed для передачи большого файла.

Для разделения файлов и работс большими потоками ниже ссылки могут вам помочь:

Несколько файлов в одном потоке, пользовательский поток
Лучший способ вернуть большой файл в виде разделенных zip-файлов, Stream или Byte arrayWCF

это также может помочь вам

Несколько потоков в одном потоке не будут правильно переданы клиенту

0 голосов
/ 19 января 2019

OutOfMemoryException говорит, что процесс использует максимальное количество памяти, которое ему разрешено. Вы отлаживаете код, пытаясь загрузить этот большой файл? Ваша IDE может быть причиной этой проблемы. Более того, на мой взгляд, при загрузке больших файлов лучше всего разделить файл на более мелкие буферы и заново создать их на стороне сервера. Другой подход может использовать FTP между сервером и клиентом для обработки самой загрузки-выгрузки.

...