2011-11-30 34 views
8

Tôi có một lớp học giữ một đại biểu, để đánh giá một cách lười biếng một cái gì đó sau này.GC của các đại biểu, tôi đang thiếu gì? (đại biểu của tôi không được thu thập)

Khi tôi đã đánh giá nó, bằng cách gọi cho đại biểu, tôi xóa tài liệu tham khảo cho đại biểu, hy vọng rằng nó sẽ đủ điều kiện để thu thập. Sau khi tất cả, nó có thể giữ cho một thế giới của các biến địa phương nếu nó được xây dựng như một phương pháp vô danh.

Tôi đã thử xây dựng một đơn vị kiểm tra để xác minh điều này, nhưng dường như không đúng cách tôi lên kế hoạch, thay vào đó có vẻ như giả định của tôi về WeakReference (mà tôi đã sử dụng cho mục đích thử nghiệm ở đây) giả định khác, không giữ nước.

Hãy nhìn vào mã này, mà bạn có thể chạy trong LINQPad

void Main() 
{ 
    WeakReference wr; 
    Lazy<int> l; 
    CreateTestData(out wr, out l); 

    wr.IsAlive.Dump();     // should be alive here 

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

    wr.IsAlive.Dump();     // and alive here as well 
    l.Value.Dump();      // but now we clear the reference 

    GC.Collect();      // so one of these should collect it 
    GC.WaitForPendingFinalizers(); 
    GC.Collect(); 

    wr.IsAlive.Dump();     // and then it should be gone here 
    GC.KeepAlive(l); 
} 

void CreateTestData(out WeakReference wr, out Lazy<int> l) 
{ 
    Func<int> f =() => 10; 
    wr = new WeakReference(f); 
    l = new Lazy<int>(f); 
} 

public class Lazy<T> 
{ 
    private Func<T> _GetValue; 
    private T _Value; 

    public Lazy(Func<T> getValue) 
    { 
     _GetValue = getValue; 
    } 

    public T Value 
    { 
     get 
     { 
      if (_GetValue != null) 
      { 
       _Value = _GetValue(); 
       _GetValue = null; 
      } 
      return _Value; 
     } 
    } 
} 

tôi đã giả định rằng:

  1. Bất kể build DEBUG, debugger đính kèm, kể từ khi tôi tạo ra các đại biểu trong một phương pháp riêng biệt, mà tôi trở về từ, không có gì giữ cho đại biểu, ngoại trừ WeakReference và các đối tượng Lazy<T>
  2. Nếu tôi yêu cầuĐối tượng 210 để từ bỏ tham chiếu của nó với đại biểu, sẽ giảm tham chiếu đến chỉ số mà WeakReference đang giữ trên
  3. Sau đó bắt buộc thu thập rác đầy đủ, giả sử rằng tham chiếu duy nhất còn lại là tham chiếu trong WeakReference
  4. Sau đó, các đại biểu sẽ được thu thập, và WeakReference tôi sẽ chỉ ra rằng đối tượng không còn sống

Đầu ra của mã đã được như vậy, dự kiến ​​sẽ được (với ý kiến):

true // not gc'ed after construction 
true // not gc'ed after full GC, still beind held by Lazy<T> 
10 // value from calling delegate 
false // but is now gc'ed, Lazy<T> no longer has a reference to it 

Nhưng thay vì đầu ra là:

true 
true 
10 
true 

bất cứ ai có thể làm sáng tỏ về những gì tôi đang thiếu ở đây?

Trả lời

6

"Sự cố" là trình biên dịch nhận thấy rằng nó có thể sử dụng lại một cá thể đại biểu duy nhất mãi mãi. Nó không nắm bắt bất kỳ bối cảnh nào, thậm chí không phải tham chiếu this tiềm ẩn. Vì vậy, đây:

void CreateTestData(out WeakReference wr, out Lazy<int> l) 
{ 
    Func<int> f =() => 10; 
    ... 
} 

là biến thành một cái gì đó như:

static Func<int> hiddenDelegate; 

static int HiddenMethod() 
{ 
    return 10; 
} 

void CreateTestData(out WeakReference wr, out Lazy<int> l) 
{ 
    if (hiddenDelegate == null) 
    { 
     hiddenDelegate = HiddenMethod; 
    } 

    Func<int> f = hiddenDelegate; 
    ... 
} 

Nhìn vào mã trong ildasm (hoặc Reflector không có tối ưu hóa bật) để xem chính xác những gì đang xảy ra.

+0

Ok, điều đó có ý nghĩa. Tôi đã thay đổi các đại biểu để nó được sử dụng một biến địa phương để tính toán kết quả của nó thay vào đó, và đó thực sự là thu thập. –

+0

Câu hỏi phụ: Tôi giả định trình biên dịch không đủ thông minh để nhận thấy rằng nhiều đại biểu, cùng loại, trả về cùng một giá trị không đổi, có thể được tạo một lần và sử dụng lại ở mọi nơi? –

+0

Về cơ bản, mục tiêu của tôi là có một bài kiểm tra xác minh rằng tham chiếu đến đại biểu được từ bỏ vào đúng thời điểm, để có thể thu thập rác ở nơi được phép, không nhất thiết là đại biểu cụ thể đó đã được thu thập.Thay đổi đại biểu chỉ giải quyết được chút ít vấn đề đó và các thử nghiệm hiện chạy như mong đợi. –

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