2011-01-07 69 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; 
     } 
    } 
}