хотите повторно использовать MemoryStream
Мой код использует MemoryStream для сериализации / десериализации объектов в / из сети. Я хотел бы повторно использовать один поток памяти в моем классе, а не создавать новый каждый раз, когда мне нужно чтобы послать что-нибудь по проводу.
Кто-нибудь знает, как это сделать?
Фрагмент кода:
// Serialize object to buffer
public byte[] Serialize(object value)
{
if (value == null)
return null;
MemoryStream _memoryStream = new MemoryStream();
_memoryStream.Seek(0, 0);
_bf.Serialize(_memoryStream, value);
return _memoryStream.GetBuffer();
}
// Deserialize buffer to object
public object Deserialize(byte[] someBytes)
{
if (someBytes == null)
return null;
MemoryStream _memoryStream = new MemoryStream();
_memoryStream.Write(someBytes, 0, someBytes.Length);
_memoryStream.Seek(0, 0);
var de = _bf.Deserialize(_memoryStream);
return de;
}
Спасибо!
2 ответа:
Во-первых, ваш метод сериализации имеет ошибку:
Обратите внимание, что буфер содержит выделенные байты, которые могут быть неиспользуемыми. Например, если строка "test" записана в объект MemoryStream, длина буфера, возвращаемого из GetBuffer, составляет 256, а не 4, при этом 252 байта не используются. Чтобы получить только данные в буфере, используйте метод ToArray; однако ToArray создает копию данных в памяти.То есть массив возвращает больше, чем сериализованный данные
Для десериализации можно построить поток памяти, который использует переданный массив, поэтому он не будет выделять внутренние буферы. Но если у вас нет тестов, которые показывают, что распределение потока памяти действительно является узким местом, я бы не беспокоился.
Если вы действительно хотите оптимизировать распределение памяти, вам нужно будет повторно использовать буферы
byte[]
. Это, в частности, означает изменение api для работы с подразделами массивов, так что размер сообщения и размер массива не должны быть идентичный.Ниже приведены детали реализации, которые могут измениться в любое время(и, возможно, уже изменились с тех пор, как я прочитал об этом):
Конечно, не стоит беспокоиться, если буферы не попадают в большую кучу объектов. Если объекты небольшие, они будут дешево собраны в следующей коллекции Gen0. Большая куча объектов, с другой стороны, непосредственно заканчивается в Gen2. Там расположены объекты AFAIR >250kB.И, конечно же, повторно использовать буферы, никогда не сокращаясь это может быть утечка памяти.
Повторное использование того же самого
MemoryStream
не дает вам никакого преимущества в производительности.Есть причина, по которой
Если вы посмотрите на внутренние части класса, вы увидите, что он выделяет буфер, и при записи, если его буфер заполняется, он выделяет новый буфер и копирует существующие байты, а затем продолжает. Таким образом, в некотором смысле буфер является неизменяемым.MemoryStream
не имеет ясного. Потому что очистить его будет дороже, чем создать новый.Это можно увидеть здесь на установка емкости, которая вызывается
EnsureCapacity()
на момент написания:public virtual int Capacity { get { if (!this._isOpen) { __Error.StreamIsClosed(); } return (this._capacity - this._origin); } [SecuritySafeCritical] set { if (value < this.Length) { throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity")); } if (!this._isOpen) { __Error.StreamIsClosed(); } if (!this._expandable && (value != this.Capacity)) { __Error.MemoryStreamNotExpandable(); } if (this._expandable && (value != this._capacity)) { if (value > 0) { byte[] dst = new byte[value]; if (this._length > 0) { Buffer.InternalBlockCopy(this._buffer, 0, dst, 0, this._length); } this._buffer = dst; } else { this._buffer = null; } this._capacity = value; } } }