хотите повторно использовать 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;
        }
    }
}