2009-11-05 15 views
12

Hệ thống: Windows XP SP3, .NET 3.5, RAM 4GB, Kép 1.6gHzLàm cách nào để đảm bảo WPF phát hành BitmapSource lớn từ Bộ nhớ?

Tôi có ứng dụng WPF tải và chuyển đổi (sử dụng hoạt ảnh của Storyboard) PNG cực lớn. Các PNG này có độ phân giải 8190x1080. Khi ứng dụng chạy nó xuất hiện để cache hình ảnh và bộ nhớ hệ thống từ từ tăng lên. Cuối cùng nó làm tắc nghẽn hệ thống và ném OutOfMemoryException.

Dưới đây là các bước Tôi hiện đang dùng để cố gắng giải quyết này:

1) Tôi đang loại bỏ các đối tượng BitmapSource từ ứng dụng

2) Tôi đang thiết lập các BitmapSource BitmapCacheOption tới Không khi tôi tải BitmapSource

3) Tôi đang đóng băng BitmapSource sau khi được tải.

4) Tôi đang xóa tất cả các tham chiếu đến Hình ảnh sử dụng nguồn cũng như bất kỳ tham chiếu nào đến chính nguồn đó.

5) Gọi thủ công GC.Collect() sau khi các bước trên đã hoàn tất.

Hy vọng tìm ra lý do tại sao WPF được treo vào bộ nhớ cho những hình ảnh này và một giải pháp có thể để đảm bảo rằng bộ nhớ được sử dụng để tải chúng được phục hồi đúng cách.

Trả lời

21

Bạn chắc chắn đã thực hiện rất nhiều công việc về vấn đề này. Tôi nghĩ rằng vấn đề chính là BitmapCacheOption.None không ngăn chặn BitmapDecoder cơ bản (s) từ được lưu trữ.

Có một số giải pháp khó khăn này như làm một GC.Collect(), tải 300 hình ảnh nhỏ từ 300 URI khác nhau, và kêu gọi GC.Collect() một lần nữa, nhưng một trong những đơn giản là đơn giản:

Thay vì tải từ một Uri, chỉ cần xây dựng một Stream và chuyển nó cho nhà xây dựng của BitmapFrame:

var source = new BitmapImage(); 
using(Stream stream = ...) 
{ 
    source.BeginInit(); 
    source.StreamSource = stream; 
    source.CacheOption = BitmapCacheOption.OnLoad; // not a mistake - see below 
    source.EndInit(); 
} 

Lý do này nên làm việc là tải từ một dòng hoàn toàn vô hiệu hóa bộ nhớ cache. Không chỉ là nguồn cấp cao nhất không được lưu trữ, nhưng không có bộ giải mã nội bộ nào được lưu trong bộ nhớ cache.

Tại sao BitmapCacheOption.OnLoad? Nó có vẻ phản trực giác, nhưng cờ này có hai hiệu ứng: Nó cho phép lưu bộ nhớ đệm nếu bộ nhớ đệm là có thể, và nó làm cho tải xảy ra tại EndInit(). Trong trường hợp bộ nhớ đệm của chúng tôi là không thể, do đó, tất cả nó làm nó gây ra tải xảy ra ngay lập tức.

Rõ ràng bạn sẽ muốn chạy mã này ra khỏi chuỗi giao diện người dùng của mình, sau đó đóng băng BitmapSource để bạn có thể di chuyển nó qua.

Bạn cũng có thể tự hỏi tại sao tôi không sử dụng BitmapCreateOptions.IgnoreImageCache. Khác với thực tế là bộ nhớ đệm là không thể bất kỳ không có URI được đưa ra, các IgnoreImageCache không hoàn toàn bỏ qua bộ nhớ cache hình ảnh: Nó chỉ bỏ qua nó để đọc. Vì vậy, ngay cả khi IgnoreImageCache được đặt, hình ảnh được tải vẫn được chèn vào bộ nhớ cache. Sự khác biệt là hình ảnh hiện có trong bộ nhớ cache bị bỏ qua.

+0

BitmapSource source = new BitmapSource() sẽ không biên dịch và tôi không chắc tại sao. Ném lỗi này: Lỗi Không thể tạo một thể hiện của lớp trừu tượng hoặc giao diện 'System.Windows.Media.Imaging.BitmapSource' – discorax

+0

Ahh..it biên dịch khi tôi sử dụng BitmapImage thay vì BitmapSource. Bây giờ, điều đó sẽ gây ra vấn đề gì? :) – discorax

+0

Cách tiếp cận này có vẻ hứa hẹn cho đến nay. Tôi sẽ tiếp tục thử nghiệm. – discorax

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