хотите повторно использовать MemoryStream
мой код использует 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
не имеет clear. Потому что было бы дороже очистить его, чем создать новый.
если вы посмотрите на внутренние части класса, вы увидите, что он выделяет буфер, и при записи, если его буфер заполняется, он выделяет новый буфер и копирует существующие байты, а затем продолжает. таким образом, буфер неизменный.
Это можно увидеть здесь при настройке емкости, которая называется 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;
}
}
}