想重用MemoryStream

Jac*_*cko 7 c# memorystream reset

我的代码使用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;
    }
Run Code Online (Sandbox Code Playgroud)

谢谢!

Ali*_*tad 10

重复使用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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `SetLength(0)`实际上是清楚的.我猜它通过重用缓冲区提供了性能优势(适用于大缓冲区).但可能仍然不值得麻烦. (4认同)

Cod*_*aos 8

首先你的序列化方法有一个bug:

请注意,缓冲区包含可能未使用的已分配字节.例如,如果将字符串"test"写入MemoryStream对象,则从GetBuffer返回的缓冲区长度为256而不是4,未使用252个字节.要仅获取缓冲区中的数据,请使用ToArray方法; 但是,ToArray会在内存中创建数据副本.

即数组返回大于序列化数据

对于反序列化,您可以构造一个使用传入数组的内存流,因此它不会分配内部缓冲区.但除非你有基准测试表明内存流分配确实是一个瓶颈我不会打扰.

如果您真的想要优化内存分配,则需要重用byte[]缓冲区.这尤其意味着修改api以使用数组的子部分,因此消息大小和数组大小不需要相同.

以下是可以随时更改的实现细节(自从我读到它之后可能已经发生了变化):
如果缓冲区没有在大对象堆上结束,那肯定不值得打扰.如果对象很小,它们将在下一代Gen0集合上便宜地收集.另一方面,大对象堆直接在Gen2中结束.AFAIR对象> 250kB在那里分配.

当然,重复使用缓冲区而不会缩小它们可能是内存泄漏.