2011-01-07 28 views
7

Mã của tôi sử dụng MemoryStream để sắp xếp/deserialize đối tượng đến/từ mạng. Tôi muốn sử dụng lại một MemoryStream duy nhất trong lớp của mình, thay vì tạo một MemoryStream mới mỗi lần tôi cần để gửi một thứ gì đó qua dây.muốn sử dụng lại MemoryStream

Có ai biết cách thực hiện việc này không?

Đoạn mã:

// 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; 
    } 

Cảm ơn!

+7

Lý do để sử dụng lại luồng là gì? Nó âm thanh như một cách khá dễ dàng để giới thiệu memoryleaks và khó gỡ lỗi mã. –

+1

+1 trên nhận xét của @Richard. Đừng làm điều này trừ khi bạn đã lược tả mã và thấy đây là vấn đề về hiệu suất hoặc bộ nhớ. –

+0

Cảm ơn các bạn.Tôi đoán tôi quên những gì một người đã từng nói về tối ưu hóa sớm ...... – Jacko

Trả lời

8

Trước hết phương pháp sắp đặt của bạn có một lỗi:

Lưu ý rằng bộ đệm chứa các byte được cấp phát có thể không được sử dụng. Ví dụ, nếu chuỗi "test" được ghi vào đối tượng MemoryStream, chiều dài của bộ đệm được trả về từ GetBuffer là 256, không phải là 4, với 252 byte không được sử dụng. Để chỉ lấy dữ liệu trong bộ đệm, sử dụng phương thức ToArray; tuy nhiên, ToArray tạo ra một bản sao của dữ liệu trong bộ nhớ.

ví dụ: lợi nhuận mảng lớn hơn các dữ liệu serialized

Đối deserializing bạn có thể xây dựng một dòng bộ nhớ trong đó sử dụng thông qua trong mảng, vì vậy nó sẽ không phân bổ bộ đệm bên trong. Nhưng trừ khi bạn có điểm chuẩn cho thấy rằng phân bổ luồng bộ nhớ thực sự là một nút cổ chai tôi sẽ không bận tâm.

Nếu bạn thực sự muốn tối ưu hóa phân bổ bộ nhớ, bạn sẽ cần phải sử dụng lại bộ đệm byte[]. Điều này đặc biệt có nghĩa là sửa đổi api để làm việc với các phần con của mảng sao cho kích cỡ thư và kích thước mảng không cần phải giống nhau.

Sau đây là chi tiết thực hiện mà có thể thay đổi bất cứ lúc nào (và có thể đã thay đổi kể từ khi tôi đọc về nó):
Đó chắc chắn không đáng làm phiền nếu bộ đệm không kết thúc trên đống đối tượng lớn. Nếu các vật thể nhỏ, chúng sẽ được thu thập rẻ tiền trong bộ sưu tập Gen0 tiếp theo. Heap đối tượng lớn, mặt khác trực tiếp kết thúc trong Gen2. Đối tượng AFAIR> 250kB được cấp phát tại đó.

Và tất nhiên việc sử dụng lại bộ đệm mà không bao giờ thu nhỏ chúng có thể là rò rỉ bộ nhớ.

+0

+1 cho quan sát tuyệt vời. – Aliostad

+0

Wow, cảm ơn, CodeInChaos !! Tôi đã tự hỏi tại sao tôi đã nhận được 256 byte mảng. – Jacko

12

Sử dụng lại cùng một MemoryStream không cung cấp cho bạn bất kỳ lợi ích hiệu suất nào.

Có một lý do tại sao MemoryStream không rõ ràng. Bởi vì nó sẽ đắt hơn để xóa nó hơn là tạo một cái mới.

Nếu bạn nhìn vào bên trong lớp, bạn có thể thấy rằng nó phân bổ bộ đệm và khi viết, nếu bộ đệm của nó đầy, nó cấp phát bộ đệm mới và sao chép các byte hiện có rồi tiếp tục. Vì vậy, trong một cách bộ đệm là không thay đổi.

này có thể được nhìn thấy ở đây ở cài đặt công suất mà được gọi bằng EnsureCapacity() tại thời điểm viết:

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; 
     } 
    } 
} 
+3

'SetLength (0)' là một cách rõ ràng. Và tôi đoán nó cung cấp lợi ích hiệu suất (đối với bộ đệm lớn) bằng cách sử dụng lại bộ đệm. Nhưng có lẽ vẫn không đáng để gặp rắc rối. – CodesInChaos

+0

Cảm ơn bạn Aliostad. Hãy làm cho nó thêm ý nghĩa hơn. – Jacko

Các vấn đề liên quan