2009-04-14 31 views
12

GC.Collect xuất hiện để bắt đầu thu gom rác trong chuỗi nền và sau đó quay lại ngay lập tức. Làm thế nào tôi có thể chạy đồng thời GC.Collect - tức là, chờ thu gom rác hoàn thành?Chạy GC. Thu thập đồng bộ

Đây là ngữ cảnh của các thử nghiệm NUnit. Tôi đã thử thêm cài đặt gcConcurrent vào tệp app.config của hội đồng kiểm tra của tôi và tôi đã thử cùng với nunit.exe.config. Không có bất kỳ hiệu ứng nào - khi tôi gỡ lỗi, tôi vẫn có thể thấy trình hoàn thiện đang chạy trên "Chủ đề kết thúc GC", chứ không phải là luồng được gọi là GC.Collect ("TestRunnerThread") của NUnit và cả hai luồng đều chạy đồng thời.

Thông tin cơ bản: Tôi muốn thử nghiệm của mình thất bại nếu chúng bị rò rỉ (không gọi Dispose on) là một lớp cụ thể. Vì vậy, tôi đã thêm một finalizer cho lớp đó đặt một lá cờ tĩnh wasLeaked; sau đó thử nghiệm của tôi TearDown gọi GC.Collect() và sau đó ném nếu wasLeaked là đúng sự thật. Nhưng nó không thất bại về mặt xác định, bởi vì khi nó đọc wasLeaked, finalizer thường chưa được gọi. (Nó không một số xét nghiệm sau đó thay vào đó, sau khi thu gom rác thải cuối cùng kết thúc.)

Trả lời

12

Trình hoàn thành được chạy trên một chuỗi nền ưu tiên cao, chuyên dụng. Từ nền trong bài viết của bạn, tôi thu thập rằng bạn chỉ có thể làm

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

Các Collect() sẽ sắp xếp bất kỳ trường hợp không bắt nguồn từ quyết toán và sau đó thread sẽ chờ cho thread finalizer để hoàn thành.

+0

Hoàn hảo! Điều này thật đúng với gì mà tôi đã tìm kiếm. Cảm ơn! –

5

Bạn có thể sử dụng GC.RegisterForFullGCNotification, kích hoạt một bộ sưu tập đầy đủ với GC.Collect(GC.MaxGeneration) và sau đó là GC.WaitForFullGCCompleteGC.WaitForPendingFinalizers phương pháp, nhưng hãy chắc chắn để sử dụng này chỉ trong các bài kiểm tra của bạn, chúng không nên được sử dụng cho mã sản xuất.

+0

Các tài liệu nói rằng WaitForFullGCApproach và WaitForFullGCComplete sẽ luôn được sử dụng cùng nhau. Làm cách nào để đợi phương pháp GC khi tôi kích hoạt GC một cách rõ ràng? Bạn có một mẫu mã thực hiện điều này? –

+0

Xin lỗi vì câu trả lời muộn. Có một lời giải thích và mẫu tốt ở đây nên ít nhiều áp dụng cho mã của bạn: http://msdn.microsoft.com/en-us/library/cc713687.aspx Bạn có thể chọn giới hạn thông báo tiếp cận của mình để về cơ bản bạn được thông báo ngay lập tức. – Lucero

2

Cách dễ dàng hơn/tốt hơn để thực hiện việc này có thể là sử dụng chế nhạo và kiểm tra kỳ vọng rằng Vứt bỏ được gọi một cách rõ ràng.

Ví dụ sử dụng RhinoMocks

public void SomeMethodTest() 
{ 
    var disposable = MockRepository.GenerateMock<DisposableClass>(); 

    disposable.Expect(d => d.Dispose()); 

    // use constructor injection to pass in mock `DisposableClass` object 
    var classUnderTest = new ClassUnderTest(disposable); 

    classUnderTest.SomeMethod(); 

    disposable.VerifyAllExpectations(); 
} 

Nếu phương pháp này cần xây dựng và sau đó xử lý các đối tượng, sau đó tôi sẽ sử dụng và tiêm một lớp nhà máy đó là khả năng tạo ra các đối tượng giả. Ví dụ dưới đây sử dụng sơ khai trên nhà máy vì nó không phải là những gì chúng tôi đang thử nghiệm trong thử nghiệm này.

public void SomeMethod2Test() 
{ 
    var factory = MockRepository.Stub<DisposableFactory>(); 
    var disposable = MockRepository.GenerateMock<DisposableClass>(); 

    factory.Stub(f => f.CreateDisposable()).Return(disposable);   
    disposable.Expect(d => d.Dispose()); 

    // use constructor injection to pass in mock factory 
    var classUnderTest = new ClassUnderTest(factory); 

    classUnderTest.SomeMethod(); 

    disposable.VerifyAllExpectations(); 
} 
+0

Đây là một cách tiếp cận tốt đẹp để kiểm tra bản phát hành xác định, nhưng không kiểm tra xem mã finalizer có hoạt động chính xác hay không. Do đó Joe có thể muốn sử dụng cả hai cách tiếp cận, tùy thuộc vào những gì anh ta muốn kiểm tra chính xác. – Lucero

+0

Tôi hiểu rằng đó là để đảm bảo rằng tất cả các lớp học của ông được gọi là Vứt bỏ (3 đoạn). – tvanfosson

+0

Mẫu Dispose sử dụng phương thức Dispose (bool disposing) được bảo vệ (được gọi là bool disposing) và được gọi bởi IDIsposable.Vứt bỏ với vứt bỏ = true và bởi finalizer (nếu cần) với disposing = false. Vì vậy, tôi không chắc chắn đường dẫn mã để vứt bỏ có nghĩa là gì. – Lucero

2

finalizers luôn chạy trên một sợi riêng biệt bất kể bạn đang sử dụng GC đồng thời hay không. Nếu bạn muốn đảm bảo rằng finalizers đã được chạy, hãy thử GC.WaitForPendingFinalizers để thay thế.

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