5

Gần đây tôi đi qua SO article này và tinh chỉnh nó cho kịch bản của tôi mà sau:Tại sao việc sử dụng Object Initializer giữ một đối tượng còn sống?

using System; 
using System.Collections.Generic; 

namespace ConsoleApplication18 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Manager mgr = new Manager(); 
      var obj = new byte[1024]; 

      var refContainer = new RefContainer(); 
      refContainer.Target = obj; 

      obj = null; 

      mgr["abc"] = refContainer.Target; 

      GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
      Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj") 

      refContainer = null; 

      GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
      Console.WriteLine(mgr["abc"] != null); // false (no remaining refs)   
     } 
    } 

    class RefContainer 
    { 
     public object Target { get; set; } 
    } 

    class Manager 
    { 
     Dictionary<string, WeakReference> refs = 
     new Dictionary<string, WeakReference>(); 
     public object this[string key] 
     { 
      get 
      { 
       WeakReference wr; 
       if (refs.TryGetValue(key, out wr)) 
       { 
        if (wr.IsAlive) 
         return wr.Target; 
        refs.Remove(key); 
       } 
       return null; 
      } 
      set 
      { 
       refs[key] = new WeakReference(value); 
      } 
     } 
    } 
} 

Chạy chương trình này cung cấp cho các kết quả dự kiến ​​như sau:

True 
False 
Press any key to continue . . . 

Tuy nhiên thay đổi này:

var refContainer = new RefContainer(); 
refContainer.Target = obj; 

Để điều này (sử dụng cú pháp Object Initializer):

var refContainer = new RefContainer() { Target = obj }; 

Cung cấp đầu ra sau đây:

True 
True 
Press any key to continue . . . 

gì đang xảy ra ở đây? Tại sao tuổi thọ của tham chiếu lại khác nhau chỉ vì sử dụng Object Initializer?

+0

Hmm ... nó in "False, False" cho tôi. Tôi không thể in được nó. Bạn đang chạy điều này dưới trình gỡ rối? Gỡ lỗi hoặc xây dựng bản phát hành? –

+0

@ JonSkeet-Chạy dưới trình gỡ lỗi, vâng. – Jim

+0

Tôi đã thử nó với các bài kiểm tra đơn vị, kết quả tương tự như được đăng. Nó khá thú vị, và thatswhy bạn không nên gây rối với GC: D –

Trả lời

7

Tại sao thời gian tồn tại của tham chiếu khác nhau chỉ vì sử dụng Trình khởi tạo đối tượng?

tôi có thể không thực sự sinh sản vấn đề của bạn dù sao, nhưng tôi nghi ngờ đó là bởi vì này:

var refContainer = new RefContainer() { Target = obj }; 

tương đương với:

var tmp = new RefContainer(); 
tmp.Target = obj; 
var refContainer = tmp; 

... do đó, bạn kết thúc với một tham chiếu thêm vào đối tượng trên ngăn xếp. Bây giờ khi chạy không dưới trình gỡ lỗi, tôi muốn mong đợi GC sẽ thông báo rằng vị trí ngăn xếp không bao giờ được đọc lại và cho phép đối tượng bị thu gom rác - nhưng khi bạn đang chạy dưới trình gỡ lỗi, GC bảo thủ, và tôi nghi ngờ nó xử lý tất cả biến ngăn xếp dưới dạng gốc GC.

Đó chỉ là phỏng đoán - dù không thể tái tạo nó, thật khó để nói chắc chắn.

CHỈNH SỬA: Bài tập của bạn là obj = null;refContainer = null; là vô nghĩa trong chế độ không gỡ lỗi; bởi vì các biến không phải là đọc sau thời điểm đó, GC bỏ qua chúng dưới dạng gốc GC.

+0

Vì vậy, ý định của tôi là xác định xem một WeakReference có thể được sử dụng để xác định một cách đáng tin cậy nếu một đối tượng không còn được tham chiếu và do đó thực hiện một số hành động với một đối tượng có chứa. Đây có phải là một ý tưởng tốt? – Jim

+0

@Jim: Ý bạn là bạn muốn thực hiện một số hành động khi đối tượng * không * tham chiếu nữa? Bởi vì tham chiếu yếu sẽ mất mục tiêu của nó ... –

+0

Vâng, đó là những gì tôi muốn làm. Về cơ bản, khi số lượng tham chiếu đến 0, hãy làm điều gì đó. – Jim

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