2011-01-07 108 views
7

我的代码使用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; 
    } 

谢谢!

+7

重复使用流的原因是什么?这听起来像是一种非常简单的方式来引入内存泄漏并且很难调试代码。 – 2011-01-07 19:56:11

+1

对@Richard的评论+1。不要这样做,除非你已经对代码进行了剖析,并发现这是一个性能或内存问题。 – 2011-01-07 19:59:32

+0

谢谢,伙计们。我想我忘了曾经有人提到过早优化的内容...... – Jacko 2011-01-07 20:25:29

回答

8

所有序列化方法首先有一个错误:

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

即阵列返回比所述串行化数据

对于反序列化可以构造,它使用在阵列所传递的存储器流大,所以不会分配内部缓冲器。但除非你有基准,这表明内存流分配真的是一个瓶颈,我不会打扰。

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

以下是可以在任何时候更改的实现细节(并且自从我阅读后可能已经发生变化):
如果缓冲区不会在大对象堆中结束,肯定不值得打扰。如果物体很小,它们将在下一代Gen0收藏中便宜地收集。另一方面,大型对象堆直接以Gen2结束。在那里分配AFAIR对象> 250kB。

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

12

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