2008-09-29 11 views
224

Trong .NET, trong trường hợp nào tôi nên sử dụng GC.SuppressFinalize()?Khi nào tôi nên sử dụng GC.SuppressFinalize()?

Lợi ích nào sử dụng phương pháp này cho tôi?

+0

Tôi đã thấy một số câu hỏi về finalizers và IDisposable, stackoverflow cũng cần phải có một cái gì đó về GC.SupressFinalize và tài liệu tham khảo yếu –

+0

Tôi không nghĩ rằng tài liệu tham khảo yếu làm nhiều của bất cứ điều gì liên quan đến finalizers - có lẽ bạn nên viết nhiều hơn câu hỏi trực tiếp về họ. –

+0

Yerp tôi có ý định đăng một câu hỏi riêng về refs yếu, tất cả điều này có thể kết hợp với nhau khi bạn xây dựng các hồ bơi đối tượng. Ngoài ra tôi nên hỏi một câu hỏi về đối tượng hồi sinh ala ReRegisterForFinalize –

Trả lời

243

SuppressFinalize chỉ nên được gọi bởi lớp có trình kết thúc. Nó thông báo cho Garbage Collector (GC) rằng đối tượng this đã được dọn sạch hoàn toàn.

Các khuyến cáo IDisposable mẫu khi bạn có một finalizer là:

public class MyClass : IDisposable 
{ 
    private bool disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       // called via myClass.Dispose(). 
       // OK to use any private object references 
      } 
      // Release unmanaged resources. 
      // Set large fields to null.     
      disposed = true; 
     } 
    } 

    public void Dispose() // Implement IDisposable 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    ~MyClass() // the finalizer 
    { 
     Dispose(false); 
    } 
} 

Thông thường, CLR giữ các tab trên các đối tượng với một finalizer khi họ được tạo ra (làm cho chúng đắt hơn để tạo ra). SuppressFinalize cho GC biết rằng đối tượng đã được dọn dẹp đúng cách và không cần phải đi đến hàng đợi finalizer. Nó trông giống như một C++ destructor, nhưng không hành động bất cứ điều gì giống như một.

SuppressFinalize tối ưu hóa không phải là tầm thường, vì đối tượng của bạn có thể sống lâu trên hàng đợi finalizer. Đừng bị cám dỗ để gọi SuppressFinalize trên các đối tượng khác tâm trí bạn. Đó là một lỗi nghiêm trọng đang chờ xảy ra.

Hướng dẫn thiết kế thông báo cho chúng tôi rằng finalizer là không cần thiết nếu đối tượng của bạn triển khai IDisposable, nhưng nếu bạn có finalizer, bạn nên triển khai IDisposable để cho phép dọn dẹp xác định lớp của bạn.

Hầu hết thời gian bạn có thể thoát khỏi IDisposable để xóa tài nguyên. Bạn chỉ cần một finalizer khi đối tượng của bạn nắm giữ vào tài nguyên không được quản lý và bạn cần phải đảm bảo rằng các nguồn lực được làm sạch.

Lưu ý: Đôi khi người lập trình sẽ thêm trình kết thúc để gỡ lỗi xây dựng các lớp IDisposable riêng của họ để kiểm tra mã đã xử lý đối tượng IDisposable của họ đúng cách.

public void Dispose() // Implement IDisposable 
    { 
     Dispose(true); 
    #if DEBUG 
     GC.SuppressFinalize(this); 
    #endif 
    } 

    #if DEBUG 
    ~MyClass() // the finalizer 
    { 
     Dispose(false); 
    } 
    #endif 
+0

Tôi đồng ý với mã của bạn nhưng tôi sẽ đặt một khẳng định vào phiên bản gỡ lỗi ... và nếu tài nguyên được xử lý là tốn kém, tôi sẽ rời khỏi finalizer trong verion phát hành. –

+1

Trong đoạn mã đầu tiên, tôi chỉ đăng những gì được đề nghị IDisposable + finalizer mẫu trông giống như. Gỡ lỗi mã là tốt, nhưng nó có thể mất tập trung. .. Tôi chỉ có thể khuyên bạn nên tránh finalizers trừ các lớp học có tài nguyên không được quản lý. Viết mã finalizer an toàn là không tầm thường. –

+0

Tôi có thể sử dụng xử lý mẫu trong một lớp cơ sở và mở rộng nó trong số những người khác không? –

1

Phương thức đó phải được gọi trên phương pháp Vứt bỏ đối tượng thực hiện IDisposable, theo cách này GC sẽ không gọi trình kết thúc lần khác nếu ai đó gọi phương thức Vứt bỏ.

Xem: http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

+6

Tôi nghĩ rằng "Phải" là sai - thậm chí không "nên" - Nó chỉ là trong một số kịch bản, bạn có thể loại bỏ các chi phí của hàng đợi/hoàn thiện đối tượng. – Basic

29

bạn đang nói với hệ thống rằng bất cứ công việc sẽ được thực hiện trong finalizer đã được thực hiện, do đó finalizer không cần phải được gọi. Từ các tài liệu .NET:

Đối tượng mà thực hiện giao diện IDisposable có thể gọi phương pháp này từ phương pháp IDisposable.Dispose để ngăn chặn các bộ thu rác từ gọi Object.Finalize vào một đối tượng mà không yêu cầu nó.

Nói chung, hầu hết mọi phương thức Dispose() đều có thể gọi GC.SupressFinalize(), vì nó sẽ dọn sạch mọi thứ sẽ được phân tách trong trình hoàn thiện.

SupressFinalize chỉ là một cái gì đó cung cấp tối ưu hóa cho phép hệ thống không bận tâm xếp hàng đối tượng vào chuỗi kết thúc. Một Dispose()/finalizer được viết đúng cách sẽ hoạt động đúng cách có hoặc không có lệnh gọi đến GC.SupressFinalize().