2009-08-12 43 views
6

Tôi có một ứng dụng WindowsForms xuất hiện để rò rỉ bộ nhớ, vì vậy tôi đã sử dụng bộ nhớ ANTS của Redgate để xem các đối tượng mà tôi nghi ngờ và thấy rằng chúng chỉ được giữ bởi các đối tượng đã có trên Finalizer Queue. Tuyệt vời, chính xác hàng đợi của Finalizer là gì? Bạn có thể chỉ cho tôi định nghĩa tốt nhất không? Bạn có thể chia sẻ bất kỳ lời khuyên giai thoại nào không?Hàng đợi cuối cùng và Kiểm soát + ThreadMethodEntry là gì?

Ngoài ra, tất cả đối tượng GC gốc trên Hàng đợi cuối cùng là các trường hợp của System.Windows.Forms.Control + ThreadMethodEntry đối tượng có tên là "người gọi". Tôi thấy rằng nó có liên quan đến tương tác giao diện người dùng đa luồng, nhưng tôi không biết nhiều hơn thế. Hãy tha thứ cho sự lười biếng rõ ràng của tôi và thừa nhận sự thiếu hiểu biết, nhưng những nguồn lực này đều được chôn cất trong một thành phần của nhà cung cấp. Tôi đang nói chuyện với nhà cung cấp về những vấn đề này, nhưng tôi cần một số hướng để giúp tôi tăng tốc về cuộc trò chuyện. Bạn có thể chỉ cho tôi định nghĩa hữu ích nhất của ThreadMethodEntry không? Bất kỳ lời khuyên giai thoại nào?

Ngoài ra, tôi có nên quan tâm đến những đối tượng này trên hàng đợi finalizer không?

Cập nhật: Điều này Red Gate article là hữu ích.

Trả lời

14

Hàng đợi finalizer giữ tất cả các đối tượng đã xác định phương thức finalizer. Nhớ lại rằng một finalizer là một phương tiện để thu thập tài nguyên không được quản lý như xử lý. Khi bộ thu gom rác thu thập rác, nó sẽ di chuyển bất kỳ đối tượng nào bằng trình hoàn thiện vào hàng đợi finalizer. Tại một số thời điểm sau-- tùy thuộc vào áp lực bộ nhớ, chẩn đoán GC và giai đoạn của mặt trăng - khi bộ thu gom rác quyết định thu thập các đối tượng này, nó đi xuống hàng đợi và chạy các finalizers.

Đã từng làm việc với rò rỉ bộ nhớ trong quá khứ, thấy một loạt các đối tượng của nhà cung cấp của bạn trong hàng đợi finalizer có thể là mã sloppy, nhưng nó không chỉ ra một rò rỉ bộ nhớ. Thông thường, mã tốt sẽ hiển thị phương thức Vứt bỏ sẽ thu thập cả tài nguyên được quản lý và không được quản lý, và khi làm như vậy, hãy xóa chính mình khỏi hàng đợi finalizer qua GC.SuppressFinalize(). Vì vậy, nếu đối tượng của nhà cung cấp thực hiện phương thức Dispose và mã của bạn không gọi nó, điều đó có thể dẫn đến một loạt các đối tượng trong hàng đợi finalizer.

Bạn đã thử tạo ảnh chụp nhanh trong ANTS giữa hai điểm trong thời gian và so sánh các đối tượng được tạo giữa chúng? Điều đó có thể giúp bạn xác định bất kỳ đối tượng được quản lý nào bị rò rỉ.

Ngoài ra, nếu bạn muốn để xem nếu bộ nhớ sẽ biến mất khi finalizers đang chạy, hãy thử này chỉ để thử nghiệm với:

 
System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); // this method may block while it runs the finalizers 
System.GC.Collect(); 

Tôi không khuyên bạn nên chạy mã này bình thường. Bạn có thể muốn chạy nó nếu bạn vừa thực hiện một tấn công việc và tạo ra rất nhiều rác. Ví dụ, trong ứng dụng của chúng tôi, một trong các chức năng của chúng tôi có thể tạo ra khoảng 350 MB rác thải sau khi đóng cửa sổ MDI. Vì điều này được biết là để lại nhiều rác, chúng tôi buộc phải thu gom rác thải theo cách thủ công.

Cũng lưu ý rằng có bộ nhớ cache thuộc tính cấp thấp trong mã Windows.Forms cơ sở sẽ giữ cho hộp thoại phương thức được mở lần cuối. Đây có thể là một nguồn rò rỉ bộ nhớ. Một cách chắc chắn để loại bỏ tham chiếu này là buộc một hộp thoại đơn giản khác xuất hiện, sau đó chạy mã GC ở trên.

+0

Cảm ơn câu trả lời tuyệt vời, Paul. Đó là đồ thị tham chiếu đối tượng tôi đang nói đến, nhìn vào các đối tượng mới trong ảnh chụp thứ hai, sau khi các tài nguyên cần được dọn sạch. Tất cả các đối tượng trong biểu đồ thực hiện IDisposable có một mẹo công cụ cho biết "Dispose() đã được gọi cho đối tượng này" nhưng đối tượng đã chọn không có chú giải công cụ như vậy. – flipdoubt

+2

Lưu ý về ThreadMethodEntry: Tôi nghĩ rằng chúng được sử dụng trong bất kỳ Invoke nào đến chuỗi giao diện người dùng. Mỗi đối tượng điều khiển có một hàng đợi của chuỗi gọi lại của loại ThreadMethodEntry. Một callback dequeues một ThreadMethodEntry và chạy nó. Mỗi đối tượng ThreadMethodEntry có một loạt các trường nội bộ. Kiểm tra các trường này có thể giúp bạn tìm ra đối tượng nào của nhà cung cấp này đang gọi. Tôi không nhớ nếu bạn có thể nhận được thông tin đó từ ANTS, nhưng tôi biết bạn có thể thông qua WinDbg.dll và sos.dll (tiện ích mở rộng trình gỡ lỗi được quản lý). Nhìn vào đại diện "phương thức" và điều khiển "người gọi". –

+0

Ngoài ra, lưu ý rằng các đối tượng ThreadMethodEntry thực hiện một finalizer, nhưng chúng không có phương thức Dispose. Khi họ hoàn thành, họ sẽ được chuyển đến hàng đợi finalizer, quá. –

1

Hàng đợi finalizer là một hàng đợi trong đó các cá thể đối tượng không được sử dụng nữa đang chờ để được GC hoàn thành. Tất cả các đối tượng trong hàng đợi này sẽ được hoàn thành và rò rỉ bộ nhớ của bạn có thể không đến từ một trong những cái này trực tiếp. Nhưng, một trong những đối tượng này có thể không giải phóng tất cả các tài nguyên không được quản lý của nó.

Lớp ThreadMethodEntry là một triển khai của IAsyncResult và các cá thể của lớp này thường được tạo khi gọi các phép toán không đồng bộ, như sử dụng Invoke để cập nhật giao diện người dùng hoặc sử dụng các phương thức Begin */End *.

0

Here's bài đăng trên blog tốt mô tả vấn đề tương tự. Ở cấp độ kỹ thuật hơn, bạn có thể xem xét sử dụng SOS.dll (bài đăng trên blog mô tả) và Sosex.dll để giúp bạn tìm ra lý do tại sao các đối tượng ThreadMethodEntry này đang treo trong bộ nhớ. Có các lệnh trong các phần mở rộng WinDbg có thể theo dõi những gì các đối tượng khác đang tham chiếu đến một đối tượng cụ thể trong bộ nhớ.

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