2011-10-09 18 views
9

Tôi có một ứng dụng trải nghiệm sự rò rỉ bộ nhớ chậm từ từ đi.Làm cách nào tôi có thể tìm thấy lý do cho hàng đợi của trình hoàn tất treo?

Sử dụng ANTS Memory Profiler Tôi có thể thấy rằng tất cả bộ nhớ bị rò rỉ đang được giữ bởi gốc GC của trình kết thúc hàng đợi.

Tôi nghi ngờ những gì có thể đã xảy ra là trình hoàn thành bị bế tắc trên khóa để có sẵn.

Không có lớp nào của chúng tôi triển khai các trình kết thúc rõ ràng, chúng tôi tránh chúng như quy tắc, điều này khiến tôi nghĩ khóa có thể liên quan đến hệ thống hoặc lớp thư viện.

Tôi đã sử dụng SOS.dll để có một cái nhìn tại các nội dung của hàng đợi finalizer và nếu tôi giải thích một cách chính xác thì nó báo cáo mục đầu tiên là một ví dụ System.Threading.Thread Tuy nhiên tôi không chắc chắn nếu người đứng đầu của hàng đợi thực sự đại diện đối tượng đang được xử lý hoặc đối tượng tiếp theo sẽ được xử lý.

  • Có bất kỳ thủ thuật nào tôi có thể sử dụng để tìm hiểu những gì đang được hoàn thành không?
  • Có cách nào tôi có thể tìm hiểu xem khóa của trình hoàn thiện đang chờ gì?
  • Có thể bật thêm bất kỳ lỗi nào để theo dõi hành động của chuỗi kết thúc không?
  • Tôi có thể xem xét điều gì khác?

Cập nhật

đống Các chủ đề finalizer xuất hiện như sau:

[email protected]() + 0x15 bytes 
[email protected]() + 0x15 bytes 
[email protected]() + 0x15 bytes  

[email protected]() + 0x43 bytes  
[email protected]() + 0x12 bytes 
ole32.dll!GetToSTA() + 0x72 bytes 

ole32.dll!CRpcChannelBuffer::SwitchAptAndDispatchCall() - 0x1939 bytes 
ole32.dll!CRpcChannelBuffer::SendReceive2() + 0xa6 bytes  
ole32.dll!CAptRpcChnl::SendReceive() + 0x5b7 bytes 
ole32.dll!CCtxComChnl::SendReceive() - 0x14b97 bytes  
ole32.dll!NdrExtpProxySendReceive() + 0x43 bytes  
[email protected]@4() + 0xe bytes  
rpcrt4.dll!_NdrClientCall2() + 0x144 bytes 
[email protected]() + 0x7a bytes  
[email protected]() + 0xf bytes 

ole32.dll!CObjectContext::InternalContextCallback() - 0x511f bytes 
ole32.dll!CObjectContext::ContextCallback() + 0x8f bytes  
clr.dll!CtxEntry::EnterContext() + 0x119 bytes 

clr.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx() + 0x2bb bytes 

clr.dll!RCWCleanupList::CleanupAllWrappers() - 0x20fb0 bytes  
clr.dll!SyncBlockCache::CleanupSyncBlocks() + 0x1ec6 bytes 
clr.dll!Thread::DoExtraWorkForFinalizer() + 0x411b5 bytes 

clr.dll!WKS::GCHeap::FinalizerThreadWorker() + 0x8b bytes 
clr.dll!Thread::DoExtraWorkForFinalizer() + 0xb6e76 bytes 
clr.dll!Thread::ShouldChangeAbortToUnload() - 0x5f8 bytes 
clr.dll!Thread::ShouldChangeAbortToUnload() - 0x53d bytes 
clr.dll!ManagedThreadBase_NoADTransition() + 0x35 bytes  
clr.dll!ManagedThreadBase::FinalizerBase() + 0xf bytes 
clr.dll!WKS::GCHeap::FinalizerThreadStart() + 0xfb bytes  
clr.dll!Thread::intermediateThreadProc() + 0x48 bytes 
[email protected]@12() + 0x12 bytes  
[email protected]() + 0x27 bytes  
[email protected]() + 0x1b bytes  
+1

Tại sao bạn tránh trình hoàn thành dưới dạng quy tắc? Thực hiện đúng mô hình dùng một lần * yêu cầu * finalizer. – svick

+2

@svick - Một lưu ý về MSDN lại. triển khai IDisposable nói "Bỏ qua finalizer hoàn toàn nếu một lớp không sở hữu tài nguyên không được quản lý" – chillitom

+1

@svick - chillitom là chính xác. Trích dẫn [Nguyên tắc thiết kế khung] (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613): "Bạn thực sự không muốn viết một finalizer nếu bạn có thể giúp nó." – TrueWill

Trả lời

9

Trông với tôi bạn đang gặp một vấn đề với một máy chủ COM. Ngăn xếp cuộc gọi cho thấy nó đang cố gắng thực hiện cuộc gọi IUnknown :: Release() trên một đối tượng COM đơn luồng. Các cuộc gọi ReleaseRCWListInCorrectCtx() đặt nó tắt, _NtUserPostMessage @ 16() là cuộc gọi mà marshals yêu cầu STA sở hữu đối tượng COM.

Nguyên nhân điển hình là tạo đối tượng COM và không bơm vòng lặp thông báo. Một yêu cầu khó khăn cho các chủ đề STA. Bạn tránh nó bằng cách tạo chúng trên luồng giao diện người dùng chính và không bao giờ chặn nó.

+1

tại chỗ, phương pháp chính của chương trình đã được đánh dấu [STAThread] để chứa chế độ GUI nhưng thường chạy dưới dạng dịch vụ cửa sổ. Gần đây, một thành phần COM phải được giới thiệu, có khả năng là ứng cử viên một Timer. Như bạn đã dự đoán không có chuỗi giao diện người dùng, trình gỡ bỏ của dịch vụ chỉ bị treo. – chillitom

+1

FYI, Nếu thread chính của bạn đang làm một cái gì đó như 'Console.ReadLine', nhưng bạn muốn nó được bơm tin nhắn, bạn có thể quay lên một Thread mới để làm readline, và sau đó sử dụng' .Join' trên nó từ chính của bạn chủ đề. Nội bộ 'Thread.Join' khi được gọi trên một thread STA sẽ bơm các tin nhắn COM, cho phép các đối tượng của bạn sử dụng nó. –

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