2016-07-08 19 views
6

thẳng vào mãhiệu ứng kỳ lạ của C đóng cửa # trên garbage collector

class Program 
{ 
    private static WeakReference<EventHandler<EventArgs>> _noClosure; 
    private static WeakReference<EventHandler<EventArgs>> _closure; 

    static void Main(string[] args) 
    { 
     Init(); 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     GC.Collect(); 
     EventHandler<EventArgs> target; 
     Console.WriteLine(_closure.TryGetTarget(out target)); 
     Console.WriteLine(_noClosure.TryGetTarget(out target)); 
    } 

    class C { public void Go() { } } 

    private static void Init() 
    { 
     _noClosure = new WeakReference<EventHandler<EventArgs>>((sender, args) => 
     { 
     }); 

     var s = new C(); 
     _closure = new WeakReference<EventHandler<EventArgs>>((sender, args) => 
     { 
       s.Go(); 
     }); 
    } 
} 

Kết quả tôi nhận được từ mã này là

False 
True 

Làm thế nào trên trái đất có thể như vậy?

P.S. Tôi đi vào điều này trong khi cố gắng tìm ra cách hoạt động của WeakEventManager.

Trả lời

6

Trình biên dịch sẽ cache đại diện _noClosure trong trường tĩnh và sử dụng lại mỗi khi bạn gọi Init. Ví dụ tương tự chính xác có thể được tái sử dụng mỗi lần.

So sánh điều đó với _closure, đóng cửa trên phiên bản mới C() trên mỗi cuộc gọi đến Init() - không thể lưu trong bộ nhớ cache.

Bộ nhớ đệm của _noClosure có nghĩa là có một tham chiếu mạnh mẽ (trường) cho người được ủy quyền, do đó không thể thu thập rác.

Nếu bạn chạy ildasm trên ứng dụng của mình, bạn có thể thấy tất cả điều này hoạt động.

+0

Đây có phải là chi tiết triển khai hay hành vi đó được nêu (ngụ ý) trong tài liệu ở đâu đó không? – ironic

+3

@ironic: Thực tế là nó * không * xảy ra là chi tiết triển khai. Thực tế là nó * có thể * xảy ra là trong spec. (Nó nói rằng cùng một đại biểu có thể được tái sử dụng, anyway.) –

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