Может ли непрерывная запись в поток без сбрасывания принудительно загружать его содержимое в кучу больших объектов?
В многопоточных настройках, таких как веб-сервер, в.NET, я обычно стараюсь избегать создания смежных блоков памяти, занимающих больше 85 КБ, так как это может привести к большой куче объектов, что может привести к проблемам с памятью.
Один из моих коллег-разработчиков использует цикл для записи в Response
, OutputStream
без Flush
кроме как в конце цикла.
Правильно ли я считаю, что не Flush
Вхождение в цикл может привести к проблемам с памятью? Как я мог доказать это?
1 ответ
Это зависит от деталей реализации используемого потока. Из документа MSDN о базовом классе Stream
Поток - это абстракция последовательности байтов, такой как файл, устройство ввода / вывода, канал межпроцессного взаимодействия или сокет TCP/IP. Класс Stream и его производные классы предоставляют общее представление об этих различных типах ввода и вывода и изолируют программиста от конкретных деталей операционной системы и соответствующих устройств.
Если разработчик этого потока не оставил каких-либо дополнительных указаний о том, как работать с несколькими последующими Write
звонки, мы должны предположить, что он обрабатывает эти детали для вас.
Я предполагаю, что вы находите этот ответ немного разочаровывающим, поэтому копайте немного глубже. Как вы говорите, ваш коллега использует Response.OutputStream
давайте посмотрим, какова основная реализация этого свойства.
get
{
if (!this.UsingHttpWriter)
{
throw new HttpException(SR.GetString("OutputStream_NotAvail"));
}
return this._httpWriter.OutputStream;
}
Так что с помощью Stream
из чего-то в _httpWriter
, Это поле содержит ссылку на экземпляр HttpWriter
, Это OutputStream
свойство инициализируется в конструкторе:
this._stream = new HttpResponseStream(this);
Класс HttpResponseStream
является внутренним, но мы можем использовать ILSpy, чтобы открыть его. это Write
Метод откладывает реализацию обратно до метода HttpWriter:
internal void WriteFromStream(byte[] data, int offset, int size)
{
if (this._charBufferLength != this._charBufferFree)
{
this.FlushCharBuffer(true);
}
this.BufferData(data, offset, size, true);
if (!this._responseBufferingOn)
{
this._response.Flush();
}
}
Как вы можете видеть, данные byte[] передаются методу, который затем копирует и сохраняет данные с помощью HttpResponseUnmanagedBufferElement
который копирует байты в память с Marshal.Copy
в буфер, который является неуправляемой памятью. Эта память выделяется блоками около 16 Кб для интегрированного конвейера и около 31 Кб для остальных.
При этом я не ожидаю, что Stream выделит столько памяти, что его внутренние структуры окажутся на LOH, потому что, судя по всему, он делает только управляемые -> неуправляемые копии памяти.
Оставляет нам свою идею регулярно звонить Flush
в петле. HttpResponseStream
имеет эту реализацию:
public override void Flush()
{
this._writer.Flush();
}
где _writer
является ранее обнаруженным HttpWriter
, Его реализация
public override void Flush()
{
}
Это верно, вызов flush будет только тратить циклы процессора. Это не поможет потоку быстрее очистить свои буферы, несмотря на многообещающую документацию в MSDN.