想重用MemoryStream

时间:2011-01-07 19:53:57

标签: c# reset memorystream

我的代码使用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 个答案:

答案 0 :(得分:11)

重复使用相同的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;
        }
    }
}

答案 1 :(得分:8)

首先,你的序列化方法有一个错误:

  

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

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

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

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

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

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