2009-04-28 7 views
40

Nhiều loại trong WPF lấy từ Freezable. Nó cung cấp tính bất biến đối với các đối tượng POCO có thể thay đổi và rõ ràng, cho phép cải thiện hiệu suất trong một số tình huống nhất định.Trong những tình huống nào, các đối tượng WPF đóng băng có hiệu suất cao?

Có ai phát hiện rằng các đối tượng đóng băng trong ứng dụng WPF của họ có cải thiện đáng kể hiệu suất không? Nếu vậy, sau đó các mặt hàng nào có sự khác biệt hiệu suất lớn nhất khi bị đóng băng?

(Lưu ý rằng tôi đã gửi similar but different question quá)

Trả lời

43

Bạn có thể quan tâm đến kinh nghiệm của tôi với Freezable:

Tôi đã từng viết một trình xem PDF bằng cách sử muPdf mà làm cho bitmap, mà tôi kết xuất với WPF. Điều gì giúp hiệu suất rất nhiều là tôi có thể hiển thị bitmap của trang trên một chuỗi nền, đóng băng chúng, và sau đó chuyển chúng vào chuỗi giao diện người dùng. Nó là tốt đẹp mà WPF không sao chép hình ảnh để đóng băng nó, nhưng khả năng để làm tất cả các chuẩn bị này trên một sợi nền là lợi ích quan trọng đối với tôi.

Từ những gì tôi hiểu, tất cả hình ảnh cần phải được cố định để chúng có thể được hiển thị một cách an toàn bằng chuỗi hiển thị WPF. Nếu bạn hiển thị hình ảnh lớn không bị đóng băng, chúng sẽ được nhân bản vô tính thành hình ảnh bị đóng băng khi WPF hiển thị chúng. Nếu bạn đóng băng các bitmap tĩnh trước, WPF có thể chỉ chia sẻ con trỏ với chuỗi render mà không cần nhân bản. Các đối tượng không được đông lạnh thậm chí có thể được sao chép nhiều lần nếu WPF không nhận biết được đối tượng được thay đổi từ lần cuối cùng nó được hiển thị. Các đối tượng đông lạnh loại bỏ sự cần thiết cho tất cả việc sao chép này.

+0

Rất hữu ích cảm ơn bạn. Tôi đã không nhận ra rằng bạn có thể làm điều này trên một chủ đề nền, nên giúp một trong các ứng dụng của tôi đáng kể! – Kelly

16

Những rò rỉ bộ nhớ tiềm năng có thể xảy ra nếu bạn sử dụng điều khiển hình ảnh (và không sử dụng phương pháp Freeze):

a) Bạn sử dụng BitmapImage như Image nguồn và không nhả BitmapImage:

static BitmapImage bi1 = new BitmapImage(new Uri("Bitmap1.bmp",UriKind.RelativeOrAbsolute)); 
m_Image1 = new Image(); 
m_Image1.Source = bi1; 
//bi1.Freeze() 
//if you do not Freeze, your app will leak memory. 
MyStackPanel.Children.Add(m_Image1); 

b) bạn gán nhiều BitmapImage là nguồn hình ảnh và không phát hành tất cả các BitmapImage bạn sử dụng (tương tự như (a)). Điều này một giới thiệu trong Net 3.5:

static BitmapImage bi1 = new BitmapImage(new Uri("Bitmap1.bmp", 
UriKind.RelativeOrAbsolute)); 
static BitmapImage bi2 = new BitmapImage(new Uri("Bitmap2.bmp", 
UriKind.RelativeOrAbsolute)); 
bi2.Freeze(); 
m_Image1 = new Image(); 
//bi1.Freeze() 
//even though you are really using bi2 for Image Source, 
//you also need to Freeze bi1 it to avoid leak 
m_Image1.Source = bi1; // use un-frozen bitmap, which causes the leak 
m_Image1.Source = bi2; // use frozen bitmap 
MyStackPanel.Children.Add(m_Image1); 

Nguồn: WPF Performance

+0

Tôi giả sử bạn đang đề cập đến các trường hợp được mô tả tại đây: https://blogs.msdn.microsoft.com/jgoldb/2008/02/04/finding-memory-leaks-in-wpf-based-applications/ (bạn nên đặt liên kết cụ thể trong câu trả lời của bạn). Tôi nghĩ điều đáng lưu ý là việc đóng băng bitmap trong các kịch bản này chỉ là một công việc xung quanh cho những gì về cơ bản có thể được coi là một ý tưởng tồi ngay từ đầu, tức là sử dụng trường 'static' để lưu trữ một bitmap mà bạn đã làm sau đó được tham chiếu trong một đối tượng 'Hình ảnh'. –

+0

Đối tượng 'Image' nhất thiết cần đăng ký thay đổi sự kiện, do đó bitmap giữ lại tham chiếu mạnh mẽ, ngăn GC của' Hình ảnh' và tất nhiên mọi thứ đã đăng ký với sự kiện thay đổi _its_. Đây thực sự là vấn đề lớn hơn mà mọi người viết mã hướng sự kiện cần phải biết: một trường 'static' có thể root toàn bộ cây đối tượng, nếu những đối tượng đó được tham chiếu gián tiếp bởi các trường sự kiện. Đóng băng một bitmap là tốt vì các lý do khác, nhưng một giải pháp tốt hơn để rò rỉ là không giữ xung quanh một đối tượng bitmap trong một trường tĩnh khi bạn không còn cần đến nó nữa (ví dụ: khi cửa sổ đóng). –

12

Mặc dù bạn đã chấp nhận câu trả lời, chỉ muốn đăng nhập một phiên bản khác của câu trả lời đã giúp tôi tốt hơn.

Từ MSDN (sửa đổi nhỏ):

Nếu bạn đã sửa đổi kiểm soát giữ tham chiếu đến các nguồn lực ở mức độ thấp không được quản lý (ví dụ: Cọ), mỗi thay đổi sẽ phải tái tạo các đối tượng ở mức độ thấp!

Lớp có khả năng tự do là điều cho phép đánh dấu khả năng để tìm các đối tượng cấp thấp, được tạo tương ứng và cập nhật chúng khi thay đổi. Khi khả năng này được kích hoạt, bàn chải được cho là để "không được đóng băng".

Phương pháp Freeze của Freeze cho phép bạn vô hiệu hóa khả năng tự cập nhật này. Bạn có thể sử dụng phương pháp này để làm cho bàn chải trở thành "bị đóng băng" hoặc không thể sửa đổi. Do đó, cải thiện hiệu suất.

Và, mã để giải thích việc sử dụng:

  Button myButton = new Button(); 
      SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow); 

      if (myBrush.CanFreeze) 
      { 
       // Makes the brush unmodifiable. 
       myBrush.Freeze(); 
      }     
      myButton.Background = myBrush;   
      if (myBrush.IsFrozen) // Evaluates to true. 
      { 
       // If the brush is frozen, create a clone and modify the clone. 
       SolidColorBrush myBrushClone = myBrush.Clone(); 
       myBrushClone.Color = Colors.Red; 
       myButton.Background = myBrushClone; 
      } 
      else 
      { 
       // If the brush is not frozen, it can be modified directly. 
       myBrush.Color = Colors.Red; 
      } 
+0

Tôi biết đây là một bài đăng cũ, nhưng một liên kết đến bài viết MSDN sẽ được tốt đẹp. – PeterM

+0

Đã cập nhật. cảm ơn. –

2

tôi đã phát triển một ứng dụng xem ảnh hiệu suất cao. Chúng tôi đã có mã trên back-end đã tạo ra một bitmap mới mỗi khung hình và viết rằng bitmap vào màn hình như vậy:

Writeablebitmap wb = new WriteableBitmap(); 
// < code to set the wb pixel values here > 

// Push the bitmap to the screen 
image.Source = wb; 

Trong thử nghiệm, chúng tôi nhận thấy rằng có một bập bùng khủng khiếp trong khi đi hơn 30 FPS với vừa phải hình ảnh cỡ (1080p). Việc sửa chữa? Chỉ cần đóng băng bitmap trước khi đặt nó vào image.Source. Không có lỗi hiệu suất diệt sản phẩm nào hơn. Ngày nay tôi cố gắng đóng băng mọi thứ tôi có thể.