2012-09-07 33 views
6

bất cứ ai có thể cho chúng tôi biết điều gì sai với mã này dưới đây? chúng tôi có ở đây một serializer đối tượng mà nên trả về một chuỗi XML của bất kỳ đối tượng được truyền cho nó.MemoryStream leak

Chúng tôi đã gãi đầu về vấn đề này vì chúng tôi có chương trình gọi nhiều lần và chúng tôi thấy mức sử dụng bộ nhớ của chúng tôi tăng cao (và ở đó ngay cả sau khi chương trình đã hoàn tất). đã thực hiện tìm kiếm nhưng không có kết quả. đối tượng luồng nằm bên trong câu lệnh "đang sử dụng" vì vậy chúng tôi nghĩ rằng điều này được cho là được xử lý theo cách riêng của nó .. hãy trợ giúp.

public static string ToXML(this IMessage m) 
    {   
     try 
     { 
      var serializer = SerializerFactory.Create(m.GetType()); 
      using (var stream = new MemoryStream()) 
      { 
       serializer.Serialize(new[] { m }, stream); 
       stream.Position = 0; 
       var s = Encoding.ASCII.GetString(stream.ToArray()); 
       return s; 
      } 
     } 
     catch (Exception e) 
     { 
      return string.Format("Message unserializable: {0}", e.Message); 
     } 
    } 

btw SerializerFactory trông như thế này:

public class SerializerFactory 
{ 
    public static IMessageSerializer Create(Type t) 
    { 
     var types = new List<Type> { t }; 
     var mapper = new MessageMapper(); 
     mapper.Initialize(types); 
     var serializer = new XmlMessageSerializer(mapper); 

     serializer.Initialize(types); 

     return serializer; 
    } 
} 
+1

Có thể không có áp lực bộ nhớ để GC chỉ thực hiện dễ dàng. – ChaosPandion

+0

Dường như không có gì rõ ràng là sai ở đây. Bạn đã thử chạy nó thông qua một bộ nhớ hồ sơ? – Dervall

+0

Có ngoại lệ nào bị ném không? Bạn đang truyền luồng tới cuộc gọi nối tiếp. Vì vậy, tôi đang có một chút nghi ngờ ở đó, tôi có nghĩa là về thời gian sống suối được mở rộng nhiều hơn nữa của nó bằng cách sử dụng locale(). – Zenwalker

Trả lời

6

Không có gì vô cùng sai với mã số đó là; lưu ý rằng usingvề cơ bản một số không trên một MemoryStream, vì nó chỉ có được quản lý tài nguyên và tài nguyên được quản lý là miền của GC; nó là bình thường cho GC không phải lo lắng rất nhiều cho đến khi nó làm cho ý nghĩa để thu thập một số bộ nhớ, vì vậy tôi sẽ không căng thẳng quá nhiều - hoặc: nếu có một vấn đề, nó có lẽ không phải là điều này.

Một quan sát, tuy nhiên, sẽ là bạn có thể tránh một bộ đệm trong bước mã hóa:

var s = Encoding.ASCII.GetString(stream.GetBuffer(), 0, (int)stream.Length); 

và trên thực tế, tôi muốn được cám dỗ sử dụng UTF8 theo mặc định, không ASCII.

Suy nghĩ cuối cùng: là tự mình SerializerFactorychính mình làm điều gì đó bị rò rỉ? Ví dụ: bạn có đang tạo một new XmlSerializer(...) qua bất kỳ nhà thầu nào phức tạp hơn phức tạp hơn không? Hình thức đơn giản:

new XmlSerializer(typeof(SomeType)); 

tốt - nó trong nội bộ lưu trữ các nội bộ/thực tế serializer mỗi loại, và tái sử dụng này cho mỗi XmlSerializer dụ tạo ra theo cách này. Tuy nhiên, nó không không làm bộ nhớ đệm này cho quá tải xây dựng phức tạp hơn: nó tạo và tải một cụm động mới mỗi lần. Và các cụm được nạp theo cách này sẽ không bao giờ được tải xuống - vì vậy có, rằng có thể gây rò rỉ bộ nhớ. Tôi sẽ rất quan tâm để xem làm thế nào các trường hợp serializer được tạo ra, để xem nếu rằng là vấn đề thực tế. Lưu ý rằng trường hợp như vậy thường rất dễ dàng để sửa chữa bằng cách tạo riêng serializer-bộ nhớ cache trong nhà máy:

public class SerializerFactory 
{ 
    // hashtable has better threading semantics than dictionary, honest! 
    private static readonly Hashtable cache = new Hashtable(); 
    public static IMessageSerializer Create(Type t) 
    { 
     var found = (IMessageSerializer)cache[t]; 
     if(found != null) return found; 

     lock(cache) 
     { // double-checked 
      found = (IMessageSerializer)cache[t]; 
      if(found != null) return found; 

      var types = new List<Type> { t }; 
      var mapper = new MessageMapper(); 
      mapper.Initialize(types); 
      var serializer = new XmlMessageSerializer(mapper); 

      serializer.Initialize(types); 

      cache[t] = serializer; 

      return serializer; 
     } 
    } 
} 
+0

đã thêm SerializerFactory làm chỉnh sửa. cảm ơn và chúng tôi sẽ có một cái nhìn về điều này – user1307017

+0

@ user1307017 chỉnh sửa để thêm một serializer-cache để 'Create' phương pháp –

+0

HOLY CRAP ... sửa đổi đã làm tất cả các phép thuật. bạn đã đúng, chúng tôi đã bắn phá chương trình của chúng tôi bằng cách sử dụng mã cũ mà không cần lưu vào bộ nhớ nào ... như 100.000 lần .. chúng tôi đã tạo các hội đồng động. giờ chúng tôi đã áp dụng bản sửa lỗi đó và mọi thứ đều hoàn hảo. cảm ơn!!! – user1307017

3

Memory rò rỉ không xảy ra trên MemoryStream, nó thực sự xảy ra trên XmlSerializer:

“Đây quá tải của các constructor XmlSerializer không bộ nhớ cache lắp ráp động được tạo ra, nhưng tạo ra một lắp ráp tạm thời mới mỗi khi bạn nhanh chóng một XmlSerializer mới! Ứng dụng đang rò rỉ bộ nhớ không được quản lý dưới dạng các hội đồng tạm thời.”

Hãy xem trên bài viết này:

http://msdn.microsoft.com/en-us/magazine/cc163491.aspx

Thay vì tạo XmlSerializer mọi lúc, bạn cần phải bộ nhớ cache đối với từng loại, để giải quyết vấn đề của bạn.

+0

cảm ơn cho lời giải thích, điều này là tương tự như của Marc. nó đã hoạt động và chúng tôi đã học được điều gì đó mới mẻ hôm nay – user1307017