2010-01-27 37 views
6

Ví dụ, trong đoạn code dưới đây một 'image'object sẽ được tạo ra và sau đó thu gom rác thải tại một số điểm chưa rõ trong tương laiCó thể viết C# để các đối tượng được thu thập rác khi chúng nằm ngoài phạm vi không?

void MyFunction() { 

    Bitmap image = RetrieveImage(); 
    DoSomething(image); 
} 

gì về

void MyFunction() { 

    DoSomething(RetrieveImage()); 

} 

Trong trường hợp này là các đối tượng rác thu thập được khi nó di chuyển ra khỏi phạm vi tức là Sau khi kết thúc MyFunction. Nếu không có một nơi nào đó để thực thi điều này?

+3

Tôi không thấy bất kỳ sự khác biệt giữa 1 und 2. Tại sao nó nên cư xử sưu tập khôn ngoan rác khác nhau? – flq

+2

Tôi không thực sự là người ủng hộ ý kiến ​​kiểu "bạn sẽ muốn điều này", nhưng nghiêm túc, bộ thu gom rác .NET thực sự biết rõ hơn lập trình viên khi đó là thời điểm tốt để dọn dẹp. hãy nhớ rằng .NET VM không phải là một hệ thống thời gian thực. Ngoài ra, nếu bạn có tài nguyên không được quản lý, hãy sử dụng IDisposable và sử dụng. –

+0

Bạn nên tin tưởng bộ thu gom rác tiêu chuẩn - rất có khả năng bạn sẽ mất hiệu suất nếu bạn buộc phải thu gom rác thải. Có lý do cụ thể nào mà bạn quan tâm khi nó xảy ra không? – jball

Trả lời

19

No. Trong thực tế, bạn không thực sự muốn nó được thu gom rác - khiến bộ thu gom rác rất thường xuyên sẽ giảm hiệu suất.

gì bạn làm muốn là để xử lý các nguồn lực không được quản lý một cách kịp thời - và đó là nơi IDisposable đến, cùng với using tuyên bố:

void MyFunction() 
{ 
    using (Bitmap image = RetrieveImage()) 
    { 
     DoSomething(image); 
    } 
} 

Đó sẽ gọi image.Dispose() vì nó rời using tuyên bố, có hoặc không DoSomething đã ném một ngoại lệ.

Bạn phải sử dụng biến thêm mặc dù - trừ khi bạn thay đổi DoSomething để có một Func<Bitmap> thay vào đó, nên thay vì:

void DoSomething(Bitmap image) 
{ 
    // Code here 
} 
... 
DoSomething(RetrieveImage()); 

bạn phải:

void DoSomething(Func<Bitmap> imageProvider) 
{ 
    using (Bitmap image = imageProvider()) 
    { 
     // Code here 
    } 
} 
... 
DoSomething(() => RetrieveImage()); 

Lưu ý rằng không cho cơ hội để vượt qua một bitmap mà không cần nó đang được xử lý - có thể là vấn đề nếu bạn muốn sử dụng lại sau. Tuy nhiên, đó là một kỹ thuật tốt đẹp để ít nhất là biết về.

EDIT: Như mbeckish đã chỉ ra trong ý kiến ​​của mình, không có nhiều lợi ích ở đây chỉ là xử lý các bitmap trong vòng RetrieveImage. Dưới đây là một biến thể trên mô hình mặc dù:

public void ApplyToEachLineInFile(string file, Action<string> action) 
{ 
    using (TextReader reader = File.OpenText(file)) 
    { 
     string line; 
     while ((line = reader.ReadLine()) != null) 
     { 
      action(line); 
     } 
    } 
} 

Ở đây, "tiếp thu và xử lý" logic được đóng gói mà không gọi lo lắng về nó - nhưng người gọi vẫn có thể rất linh hoạt về sự phức tạp của logic họ vượt qua in.

+0

Đề xuất tốt đẹp khi chuyển qua đại diện nhà cung cấp. Đó là một mô hình rất hữu ích trong nhiều trường hợp. –

+0

Tại sao điều đó tốt hơn DoSomething (RetrieveImage()); và xử lý bitmap trong DoSomething? – mbeckish

+0

Bởi vì nếu bitmap được truyền vào DoSomething, làm thế nào để DoSomething biết liệu nó có an toàn để vứt bỏ không? Điều gì sẽ xảy ra nếu người gọi muốn chuyển bitmap tới DoSomethingElse sau khi chuyển nó tới DoSomething? –

4

Thu gom rác thải không xảy ra khi vật thể rơi ra ngoài phạm vi. Thay vào đó, nó là một chức năng quản lý bộ nhớ tự động từ khung công tác.

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

Bạn có thể buộc Net để thu thập rác thải, nhưng trừ khi bạn đang gặp vấn đề bộ nhớ nghiêm trọng, tôi sẽ không khuyên bạn đi xuống con đường đó.

+0

Đồng ý, tốt nhất là để người thu gom rác thực hiện các tác vụ của chính nó một cách tự động như trái ngược với việc gọi nó theo cách thủ công. –

0

Bạn có thể thực thi Garbage Collection với:

System.GC.Collect()

Sau khi xử lý nó đúng cách (xem Jons trả lời cho sử dụng() {} - Cú pháp).

< chỉnh sửa>

Đừng quên (như tôi vừa làm)

System.GC.WaitForPendingFinalizers();

sau đó.

</chỉnh sửa>

Mặc dù không được khuyến nghị - như Jon đã nói.

+1

Gọi thu thập không * đảm bảo * rằng một đối tượng nằm ngoài phạm vi thực sự được thu thập. Có rất nhiều kịch bản thú vị và kỳ lạ trong đó một đối tượng như vậy có thể tồn tại lâu hơn nữa. Cũng lưu ý rằng bạn thường nên chờ cho finalizers đang chờ xử lý để chạy nếu bạn đang buộc một bộ sưu tập; các trình hoàn thành đang chờ xử lý chạy trên một chuỗi khác, vì vậy có thể có các cuộc đua. –

+0

Đúng. Cám ơn.Nên chỉ cần sao chép mã mà chúng tôi đã sử dụng;) – Leonidas

3

LƯU Ý: Bạn không muốn thực hiện việc này. Trình thu gom rác .NET "thông minh hơn" bạn (hoặc tôi, hoặc Jon Skeet hoặc bất kỳ ai khác).

try 
{ 
    Bitmap image = RetrieveImage(); 
    DoSomething(image); 
} 
finally 
{ 
    GC.Collect(); 
} 

(đây là giả định rằng không ai trong số các đối tượng rơi ra khỏi phạm vi thực hiện IDisposable)

+1

Lưu ý rằng để làm việc này, điều quan trọng là biến 'image' được khai báo bên trong câu lệnh' try', như đã cho. Nếu không, thời gian chạy có thể hoặc không thể xem xét đối tượng không thể truy cập được và bạn có thể sẽ thúc đẩy đối tượng đó đến thế hệ cao hơn, ngăn chặn hiệu quả đối tượng khỏi bị thu gom rác. –

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