Memorystream и Large Object Heap

Я должен передать большие файлы между компьютерами на через ненадежные соединения с помощью WCF.

Поскольку я хочу смочь возобновить файл, и я не хочу быть ограниченным в моем размере файла WCF, я разделяю файлы на блоки в части 1 МБ. Они "разделяют на блоки", транспортируются как поток. Который работает довольно хороший, до сих пор.

Мои шаги:

  1. открытый filestream
  2. считайте блок из файла в байт [] и создайте memorystream
  3. блок передачи
  4. назад к 2. пока целый файл не отправляется

Моя проблема находится на шаге 2. Я предполагаю, что, когда я создаю поток памяти из массива байтов, он закончится на LOH и в конечном счете вызовет outofmemory исключение. Я не мог на самом деле создать эту ошибку, возможно, я неправ в своем предположении.

Теперь, я не хочу отправлять байт [] в сообщении, поскольку WCF скажет мне, что размер массива является слишком большим. Я могу изменить макс. позволенный размер массива и/или размер моего блока, но я надеюсь, что существует другое решение.

Мой фактический вопрос (вопросы):

  • Мое текущее решение создаст объекты на LOH, и это вызовет меня проблема?
  • Существует ли лучший способ решить это?

Btw.: На стороне получения I простых чтений меньшие блоки от прибывающего потока и пишут им непосредственно в файл, таким образом, никакие большие включенные массивы байтов.

Править:

текущее решение:

for (int i = resumeChunk; i < chunks; i++)
{
 byte[] buffer = new byte[chunkSize];
 fileStream.Position = i * chunkSize;
 int actualLength = fileStream.Read(buffer, 0, (int)chunkSize);
 Array.Resize(ref buffer, actualLength);
 using (MemoryStream stream = new MemoryStream(buffer)) 
 {
  UploadFile(stream);
 }
}
14
задан flayn 21 May 2015 в 19:03
поделиться

2 ответа

Надеюсь, все в порядке. Это мой первый ответ на StackOverflow.

Да, безусловно, если размер вашего фрагмента превышает 85000 байт, массив будет размещен в куче больших объектов. Вы, вероятно, не очень быстро исчерпаете память, поскольку вы выделяете и освобождаете смежные области памяти, которые имеют одинаковый размер, поэтому, когда память заполняется, среда выполнения может вместить новый фрагмент в старую, освобожденную область памяти.

Я бы немного обеспокоился вызовом Array.Resize, так как он создаст другой массив (см. http://msdn.microsoft.com/en-us/library/1ffy6686 (VS.80) .aspx ). Это необязательный шаг, если actualLength == Chunksize будет использоваться для всех фрагментов, кроме последнего. Поэтому я как минимум предлагаю:

if (actualLength != chunkSize) Array.Resize(ref buffer, actualLength);

Это должно удалить много выделений.Если фактический размер не совпадает с размером chunkSize, но все еще> 85000, тогда новый массив также будет размещен в куче больших объектов, что может привести к его фрагментации и, возможно, вызвать очевидные утечки памяти. Я считаю, что на то, чтобы действительно исчерпать память, по-прежнему потребуется много времени, поскольку утечка будет довольно медленной.

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

BufferManager bm = BufferManager.CreateBufferManager(chunkSize * 10, chunkSize);

for (int i = resumeChunk; i < chunks; i++)
{
    byte[] buffer = bm.TakeBuffer(chunkSize);
    try
    {
        fileStream.Position = i * chunkSize;
        int actualLength = fileStream.Read(buffer, 0, (int)chunkSize);
        if (actualLength == 0) break;
        //Array.Resize(ref buffer, actualLength);
        using (MemoryStream stream = new MemoryStream(buffer))
        {
            UploadFile(stream, actualLength);
        }
    }
    finally
    {
        bm.ReturnBuffer(buffer);
    }
}

предполагается, что реализация UploadFile может быть переписана так, чтобы принимать int вместо no. байтов для записи.

Надеюсь, это поможет

Джо

35
ответ дан 1 December 2019 в 06:43
поделиться

Я не уверен в первой части вашего вопроса, но что касается лучшего способа - не рассматривали ли вы BITS? Он позволяет фоновую загрузку файлов по http. Вы можете предоставить ему http:// или file:// URI. Она возобновляется с того места, где была прервана, и загружает куски байтов, используя метод RANGE в http HEADER. Он используется Windows Update.Вы можете подписаться на события, которые предоставляют информацию о ходе выполнения и завершении.

2
ответ дан 1 December 2019 в 06:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: