2013-02-26 34 views
6
public class MyClass { 
    private static MyClass heldInstance; 

    public MyClass() { 
    heldInstance = this; 
    } 
} 

Giả sử một cá thể của MyClass không được bắt nguồn theo bất kỳ cách nào khác, tham chiếu tĩnh riêng tư có ngăn chặn việc thu thập rác không?Lớp học có thể tự tham chiếu trong một trường tĩnh có được thu gom rác không?

+1

bản sao có thể có của [Các thành viên tĩnh có bao giờ thu gom rác không?] (Http://stackoverflow.com/questions/6600093/do-static-members-ever-get-garbage-collected) EDIT: Tóm lại, không, Tôi không tin điều đó sẽ xảy ra. Ví dụ, trong mã bạn đã đăng, không có lý do gì mà hàm xây dựng công cộng không thể có 'if (heldInstance == null)' Khác hơn, _instances_ trong đó các tham chiếu duy nhất được giữ lại từ chính nó sẽ được thu thập _eventually_ bởi GC khi nó xác định rằng nó không còn truy cập được nữa. –

+0

Có, chúng được thu thập ngay trước khi AppDomain được tải xuống. Đó là không quan trọng trừ khi lớp học có một finalizer. –

+3

Thực tế là một trường tĩnh của lớp đang tham chiếu một cá thể * của cùng một lớp * là không liên quan. Các trường tĩnh là rễ; họ sẽ giữ bất cứ thứ gì còn sống mà bạn đưa vào chúng bất chấp loại của nó. –

Trả lời

8

Lớp bạn đăng sẽ không bị thu gom rác. Bạn có thể kiểm tra điều này bằng cách cho nó một finalizer với một giao diện điều khiển đầu ra:

public class MyClass 
{ 
    private static MyClass heldInstance; 
    public MyClass() 
    { 
     heldInstance = this; 
    } 
    ~MyClass() 
    { 
     Console.WriteLine("Finalizer called"); 
    } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var x = new MyClass(); // object created 

     x = null; // object may be eliglible for garbage collection now 

     // theoretically, a GC could happen here, but probably not, with this little memory used 
     System.Threading.Thread.Sleep(5000); 

     // so we force a GC. Now all eligible objects will definitely be collected 
     GC.Collect(2,GCCollectionMode.Forced); 

     //however their finalizers will execute in a separate thread, so we wait for them to finish 
     GC.WaitForPendingFinalizers(); 

     System.Threading.Thread.Sleep(5000); 
     Console.WriteLine("END"); 

    } 
} 

Kết quả sẽ là:

END 
Finalizer called 

Có nghĩa là lớp chỉ được thu thập tại teardown thức của ứng dụng, không trong khi thu gom rác thông thường.

Nếu bạn tạo nhiều trường hợp của lớp này như thế này:

var x = new MyClass(); 
x = new MyClass(); 
x = new MyClass(); 
x = new MyClass(); 

sau đó tất cả ngoại trừ một gần đây nhất sẽ được thu gom rác thải.

Bạn sẽ nhận được

Finalizer called 
Finalizer called 
Finalizer called 
END 
Finalizer called 
+1

Lưu ý rằng điều này là đúng chỉ vì 'heldInstance' là tĩnh. Không có gì đặc biệt về thực tế rằng một thể hiện của 'MyClass' có một tham chiếu đến chính nó. Vì vậy, có "một lớp học tham khảo chính nó" có thể được thu thập rác thải. Tuy nhiên, lớp trong ví dụ không thể. – dgvid

2

Các nhà sưu tập rác xác định đối tượng là thể truy cập và sẽ thu thập những người không được. Để xác định xem một đối tượng có thể truy cập hay không, trình thu thập sẽ bắt đầu bằng cái gọi là số gốc. Trong số các gốc là những thứ hiện có trên ngăn xếp đánh giá, nhưng cũng có các trường tĩnh . Bộ thu sẽ theo các tham chiếu đến các đối tượng từ gốc đến bất kỳ đối tượng nào và từ một đối tượng như vậy đến bất kỳ đối tượng nào khác, v.v. Mỗi đối tượng đã được truy cập theo cách này là có thể truy cập và do đó sẽ được giữ sống.

Trong trường hợp của bạn, trường tĩnh là một trong các gốc của bộ gom rác và do đó nó sẽ không bao giờ thu thập bất kỳ đối tượng nào được tham chiếu (gián tiếp) bởi trường đó. Tuy nhiên, nếu bạn đặt trường thành null thì trường đó không còn tham chiếu đến cá thể và thể hiện có thể.

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