WCF BufferManager ReturnBuffer против Clear
Я использую BufferManager в моей службе WCF. Я создал свой собственный класс, чтобы обернуть вокруг BufferManager, который реализует IDisposable. Прямо сейчас мой метод Dispose выглядит так:
public void Dispose()
{
this.bufferManager.Clear();
}
Мой вопрос: выполняет ли это то же самое, что и вызов ReturnBuffer для всех буферов, которые были приняты менеджером?
Просто для справки: я использую BufferManager в следующем методе:
public byte[] ReadAllBufferedBytes(string filePath)
{
using (var fileStream =
new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = this.bufferManager.TakeBuffer((int)fileStream.Length);
fileStream.Read(buffer, 0, buffer.Length);
return buffer;
}
}
Причина, по которой я это делаю, заключается в том, что я продолжал получать исключения OutOfMemory, которые разрушали бы сервис.
Хост-сервер имеет 3 ГБ памяти. Служба находится в режиме InstanceContextMode.Single, поэтому изображения обрабатываются по одному. Изображения принимаются в виде байтовых массивов - самые большие могут составлять 100 МБ, но обычно они гораздо меньше - преобразуются, а затем возвращаются в виде байтового массива. Многое заканчивается в куче больших объектов, а размеры изображений довольно сильно различаются.
Мне интересно, если проблема в фрагментации кучи.
Когда каждая страница документа конвертируется, она добавляется во временный файл на диске. После преобразования я считываю весь преобразованный файл с диска в байтовый массив и возвращаю его клиенту.
Стандартный метод File.ReadAllBytes создает новый байтовый массив при чтении из файла, который неизбежно заканчивается в LOH из-за размеров изображения, с которыми я работаю (полагаю, именно это и происходит). Я создал метод ReadAllBufferedBytes, чтобы сделать то же самое, но для буферизации массива байтов и позволить BufferManager возвращать буфер, когда он удаляется.
Другой вопрос: нужно ли мне все это делать?
1 ответ
BufferManager обычно используется в сценариях, где вы должны предотвратить давление ГХ - там, где много мелких byte[]
назначения, как при получении или отправке данных на очень низком уровне (например, сокеты). Акцент здесь делается на многое, в противном случае сборщик мусора должен уметь справляться с распределением памяти.
Чтобы предотвратить загрузку всего преобразованного файла документа в память, вы должны использовать FileStream напрямую (без чтения всего содержимого в память - байт []) в сочетании с потоковым (ответным) TransferMode, если это возможно.