2010-04-27 47 views
8

Vì C# sử dụng Bộ sưu tập rác. Khi nào cần sử dụng .Để giải phóng bộ nhớ?C# phân bổ bộ nhớ và các mẫu deallocation

Tôi nhận thấy có một vài tình huống nên tôi sẽ cố gắng liệt kê những tình huống mà tôi có thể nghĩ đến.

  1. Nếu tôi đóng Biểu mẫu chứa đối tượng loại GUI, các đối tượng đó có bị hủy đăng ký và do đó sẽ được thu thập không?
  2. Nếu tôi tạo một đối tượng địa phương bằng cách sử dụng mới nên tôi. Hãy sử dụng nó trước khi thoát khỏi phương pháp hoặc chỉ để cho GC xử lý nó? Thực hành tốt trong trường hợp này là gì?
  3. Có lần nào việc buộc GC có thể hiểu được không?
  4. Sự kiện có được GC thu thập khi đối tượng của nó được thu thập không?
+0

có thể trùng lặp của http://stackoverflow.com/questions/2714811/is-there-a-common-practice-how-to-make-freeing-memory-for-garbage-collector-easie –

+0

Ngoài ra, trùng lặp : http://stackoverflow.com/questions/331786/since-net-has-a-garbage-collector-why-do-we-need-finalizers-destructors-dispose Xem thêm: http://stackoverflow.com/questions/1090451/net-garbage-collector-basics http://stackoverflow.com/questions/1729289/net-garbage-collector-mystery http://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage -kiểm tra-từ-xảy ra http://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage-collection-from-occuring http://stackoverflow.com/questions/888280/ http: // stackoverflow .com/questions/371109/ –

+0

Nói chung IDisposable được thực hiện cho các tài nguyên không được quản lý sẽ không được trả lại, đóng hoặc sử dụng tối ưu khi objec t được làm sạch bởi GC - đối tượng được quản lý luôn được làm sạch bởi GC. Xem IDisposable @ http: // msdn.microsoft.com/en-us/library/system.idisposable.aspx Đối với # 2, GC xử lý các đối tượng trong mã được quản lý cho dù bạn có gọi Dispose() hay không. # 1 và được xây dựng trong "đối tượng kiểu GUI" sẽ được thu thập cho dù bạn gọi Dispose() hay không. Ngoài ra, hãy xem http://msdn.microsoft.com/en-us/magazine/bb985010.aspx –

Trả lời

10

Về lý thuyết, nếu bạn đã xác định đúng componentry, nó nên không bao giờ có cần gọi Dispose() trên đối tượng của bạn, như finalizer nên cuối cùng chăm sóc nó. Điều đó đang được nói, bất cứ khi nào bạn đang sử dụng một đối tượng triển khai IDisposable, bạn nên gọi Dispose() trên đối tượng ngay sau khi bạn làm việc với nó.

Đối với một số điểm cụ thể của bạn:

1) Nếu bạn biết bạn đang "thực hiện" với Form, bạn có thể gọi Dispose() trên đó. Điều này sẽ buộc dọn dẹp tại thời điểm đó trong các tài nguyên không được quản lý được liên kết với biểu mẫu.

2) Trong trường hợp này: nếu đối tượng của bạn chỉ được sử dụng trong phương pháp, sử dụng "sử dụng" thay vì:

using (MyObject myObject = new MyObject()) 
{ 
    // use your object 
} // It'll be disposed of here for you 

3) Có nhiều lý do hiếm để làm điều này, nhưng nói chung, không có.

4) Sự kiện là đại biểu - bộ nhớ được liên kết với người được ủy quyền sẽ được thu thập sau khi bản thân người được ủy quyền trở nên không bị bỏ qua, thường xảy ra khi các đối tượng được đề cập không được hủy bỏ.

+0

Tôi sử dụng mẫu using() {} cho tất cả các tài nguyên kiểu IO. Tôi sẽ bắt đầu sử dụng nó cho tất cả các đối tượng dùng một lần để tuân theo một mẫu nhất quán. Cảm ơn câu trả lời của bạn. – Neal

2

Nhìn vào câu hỏi này:

Is there a common practice how to make freeing memory for Garbage Collector easier in .NET?

Nếu lớp học của bạn instantiates giao diện IDisposable, đó (có lẽ) có nghĩa là nó có nguồn tài nguyên hệ thống mà phải được xử lý trực tiếp. Một cách dễ dàng để thực hiện điều đó là sử dụng từ khóa đang sử dụng, như sau:

using(var g = Graphics.FromBitmap(bmp)) 
{ 
    //Do some stuff with the graphics object 
} 

cho mỗi @Matt S câu trả lời trong câu hỏi mà tôi đã tham chiếu.

Đối với câu hỏi của bạn:

  1. Nếu bạn tạo một đối tượng có IDisposable, bạn sẽ cần phải vứt bỏ nó khi bạn đóng biểu mẫu. Đó là khó khăn trong WPF và đơn giản trong Winforms, kể từ khi hộp thoại winforms có phương pháp Vứt bỏ. Đối với WPF, tôi đã giải quyết vấn đề bằng cách giữ lớp WPF xung quanh nhưng ẩn, được gọi là phương thức vứt bỏ để phân phối tất cả các đối tượng (như cổng nối tiếp), và sau đó đặt lớp WPF thành null.
  2. No. Hãy để GC chăm sóc nó.
  3. Tôi nghĩ như vậy, nhưng tôi đã nhận được phiếu với tiêu cực :) Khi tôi đã thực hiện phân bổ rất lớn, buộc GC để loại bỏ chúng là, imo, một ý tưởng tốt.
  4. Tôi không chắc chắn. Tôi nghĩ rằng các sự kiện là, trong và của chính họ, các đối tượng, do đó sẽ được thu thập khi không còn sử dụng nữa.
+0

phản hồi # 2 của bạn dường như xung đột với mọi người khác. Tại sao bạn sẽ nói để GC chăm sóc nó? Ngoài ra nó có vẻ xung đột phần nào với tuyên bố ban đầu của bạn? – Neal

+0

Nếu bạn chỉ cần tạo một đối tượng bằng cách sử dụng mới, nhưng nó không thực hiện giao diện IDisposable, hãy để GC xử lý nó. Nhưng, nếu nó thực hiện IDisposable, sau đó bạn phải vứt bỏ nó trước khi bạn để nó đi, theo # 1. Nếu bạn khai báo một mảng ints mới, int không thực hiện IDisposable, vì vậy bạn có thể để cho gc quan tâm đến nó. – mmr

3

Bạn nên gọi Dispose trên mỗi lớp triển khai IDisposable. Nếu nó không cần phải là Dispose thì nó sẽ không thực hiện IDisposable.

Đối với các câu hỏi khác của bạn:

  1. Khi bạn thêm một điều khiển để Controls bộ sưu tập của Form, sau đó điều khiển sẽ tự động xử lý khi biểu mẫu được đóng lại, vì vậy bạn không cần phải làm gì ở đó cả.
  2. Nếu đối tượng thực hiện IDisposable, thì bạn cần gọi số Dispose. Ví dụ, nếu bạn đi new FileStream(...), thì FileStream cần phải được xử lý, vì nó thực hiện IDisposable. Tôi sẽ đề nghị bạn đọc lên trên các cấu trúc using trong C# mà làm cho nó dễ dàng hơn để xử lý các đối tượng IDisposable.
  3. Không thực sự, 99,99% thời gian, bộ thu gom rác sẽ biết thời điểm tốt nhất để chạy là. Đó là một trong số đó, "bạn sẽ biết khi nào bạn cần" loại tình huống.
  4. Khi đối tượng chứa sự kiện không còn được tham chiếu, sau đó về mặt logic bất kỳ tham chiếu đối tượng nào trong sự kiện cũng không còn được tham chiếu và sẽ có sẵn để được thu thập.
+0

# 1: Đúng nhưng nếu đối tượng được thêm vào lúc thiết kế nhưng không được thêm vào bộ sưu tập của bộ điều khiển thì sao? Nó vẫn sẽ được giải phóng khi biểu mẫu được đóng lại? # 2: Thật vậy, tôi hầu như luôn triển khai mô hình using() {} khi xử lý tài nguyên IO. # 4: Tôi đã đọc nhiều trường hợp sự kiện không thuộc tính bị xóa sẽ bị rò rỉ. Hay đúng hơn là không giải phóng bộ nhớ. Tôi nhận ra điều này chỉ có thể là một tham chiếu không đáng kể. – Neal

+0

Trên # 4, khi đối tượng * chứa * sự kiện không còn tham chiếu, một đối tượng tham chiếu đến sự kiện tự giữ cũng sẽ không được tham chiếu nữa. Vấn đề xảy ra khi bạn thêm một trình xử lý vào một sự kiện, sự kiện giữ một tham chiếu đến đối tượng đó: do đó đối tượng sẽ không được khai hoang cho đến khi sự kiện * được khai hoang hoặc bạn hủy đăng ký theo cách thủ công. Đối với hầu hết các công cụ WinForms, trình xử lý sự kiện thường ở dạng chứa, vì vậy nó thường không phải là một vấn đề. –

+0

ah Tôi thấy điều đó có ý nghĩa. Cảm ơn bạn đã làm rõ. – Neal

0

Nếu bạn đang sử dụng đối tượng IDisposable, hãy cân nhắc sử dụng câu hỏi using để tự động xử lý việc xử lý bạn.

1

Giống như Reed Copsey cho biết, thường không cần thiết phải gọi Dispose.

Trường hợp có thể có thể tạo ra sự cố của bạn là đối tượng tĩnh đang giữ tham chiếu của các đối tượng khác không còn được sử dụng ở bất kỳ nơi nào khác. Các mã sau đây cho thấy một ví dụ:

Form_Load(...) 
    MyState.Instance.AddressChanged += this.User_AddressChanged; 
End 

Nếu vì lý do nào đó, khi biểu mẫu không được hủy bỏ, mã không hủy đăng ký xử lý sự kiện, thể hiện mẫu sẽ vẫn được tham chiếu bởi đối tượng nhà nước.

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