Использование памяти ASP.net при загрузке - PullRequest
5 голосов
/ 23 января 2010

На сайте ASP.net на моем рабочем месте следующий фрагмент кода отвечает за загрузку файлов (ПРИМЕЧАНИЕ. Response.TransmitFile здесь не используется, поскольку содержимое загрузки передается из zip-файла) :

private void DownloadFile( Stream stream)
{
        int bytesRead;
        int chunkSize = 1048576; //1MB

        byte[] readBuffer = new byte[chunkSize];
        while ((bytesRead = stream.Read(readBuffer, 0, readBuffer.Length)) != 0)
            {
                if(!Response.IsClientConnected)
                    break;
                byte[] chunk = new byte[bytesRead];
                Array.Copy(readBuffer,0,chunk,0,bytesRead);
                Response.BinaryWrite(chunk);
                Response.Flush();
        }
        stream.Close();
}

Наши пользователи часто загружают файлы размером в несколько сотен МБ, которые могут довольно быстро перегружать память сервера. Я предполагаю, что это связано с буферизацией ответа. Имеет ли это смысл?

Я только что прочитал о свойстве 'buffer' объекта Response. Если я установлю это в false, это предотвратит вызовы Response.BinaryWrite () для буферизации данных в памяти? В общем, что является хорошим способом ограничения использования памяти в этой ситуации? Возможно, мне следует выполнить потоковую передачу из zip во временный файл, а затем вызвать Response.TransmitFile ()?

РЕДАКТИРОВАТЬ: В дополнение к возможным решениям меня очень интересуют объяснения проблемы использования памяти, представленной в приведенном выше коде. Почему это потребляет гораздо больше, чем 1 МБ, даже если Response.Flush вызывается на каждой итерации цикла? Является ли это просто ненужным выделением кучи, которое происходит на каждой итерации цикла (и сразу не получает GC), или есть что-то еще в работе?

1 Ответ

4 голосов
/ 23 января 2010

Вот код, над которым я работаю. Он использует 8000-байтовый буфер для отправки файла кусками. Некоторое неофициальное тестирование большого файла показало значительное уменьшение выделенной памяти.

int BufferSize = 8000;
FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
try {
  long fileSize = stream.Length;

  long dataLeftToRead = fileSize;
  int chunkLength;
  buffer = new Byte[BufferSize];

  while (dataLeftToRead > 0) {
    if (!Response.IsClientConnected) {
      break;
    }
    chunkLength = stream.Read(buffer, 0, BufferSize);

    Response.OutputStream.Write(buffer, 0, chunkLength);
    Response.Flush();

    dataLeftToRead -= chunkLength;
  }
}
finally {
  if (stream != null) {
    stream.Close();
}

отредактировано для исправления синтаксической ошибки и пропущенного значения

...