2008-10-29 31 views

Trả lời

15

Nếu đối tượng thực hiện IDisposable, bạn nên vứt bỏ nó ngay khi bạn hoàn thành nó. Cách dễ nhất là bao quanh nó với một khối using:

using (SqlCommand cmd = new SqlCommand(conn)) { 
    cmd.ExecuteNonQuery(); 
} 
0

Dựa vào GC 'hoạt động' trong hầu hết các trường hợp. Ngoại lệ cổ điển là khi bạn có một tương tác nặng tài nguyên - trong trường hợp đó là cách tốt nhất để giải quyết vấn đề.

ví dụ rõ ràng.

using (var conn = new SqlConnection(connString)) {} 

'Sử dụng' khối chắc chắn là phương pháp sạch và mạnh nhất để đảm bảo rằng vật thể được xử lý chính xác. Các khối 'Sử dụng' có thể được thừa hưởng với bất kỳ đối tượng nào triển khai IDisposable.

+0

GC hoạt động hoàn toàn do sự trùng hợp ngẫu nhiên. Nó không có nghĩa vụ gọi Dispose một cách kịp thời. – JaredPar

+0

Tôi không đề nghị GC phải thực hiện nó một cách kịp thời. Tôi cho rằng việc xử lý manaul của các đối tượng thông thường là không cần thiết. – berko

+0

Vì vậy, ví dụ, khi bạn tạo một thể hiện Bitmap, bạn không nghĩ rằng bạn cần phải vứt bỏ nó theo cách thủ công? Nghĩ lại. GC thấy rằng đối tượng 30MB là 10 byte và bỏ qua nó vô thời hạn. Nó sẽ sụp đổ máy chủ của bạn Mỗi lần duy nhất. –

-7

Khi bạn hoàn tất một đối tượng, bạn có thể quên nó. Miễn là nó không được tham chiếu bất cứ nơi nào thì nó tốt như đã biến mất. Bộ nhớ mà nó sử dụng được giải phóng khi bộ thu gom rác cảm thấy như nó.

+0

Ai đó có thể giải thích tại sao câu trả lời này bị đóng sầm như thế này? -6? Và không có cam kết? – bobobobo

+4

@bobobobo Tôi nghĩ rằng bởi vì nó không phải là địa chỉ IDisposable được dự định để cho phép một đối tượng để phát hành tài nguyên bên ngoài thời gian chạy NET khi họ không còn cần thiết thay vì chờ đợi cho GC. – ongle

3

Có một vài cách để xem nó. Một cách cố gắng tìm ra nếu nó thực sự cần thiết để vứt bỏ một đối tượng ngay khi nó không còn cần thiết, ví dụ bằng cách sử dụng Reflector để xem liệu nó thực sự có giữ tài nguyên không được quản lý hay không. Quan điểm khác là giả định rằng nếu một đối tượng thực hiện IDisposable, nó không phải là doanh nghiệp của bạn để xác định xem Vứt bỏ() thực sự cần phải được gọi là - bạn luôn luôn gọi nó. Tôi nghĩ đó là cách đi đúng đắn. Nhìn trộm vào việc thực hiện riêng của các đối tượng để đưa ra quyết định về cách bạn nên tiêu thụ chúng làm tăng nguy cơ của bạn nhận được kết hợp với một thực hiện có thể thay đổi. Một ví dụ là LINQ to SQL DataContext. Nó thực hiện IDispose nhưng chủ yếu là dọn dẹp sau chính nó mà không cần một lời gọi rõ ràng để Dispose(). Sở thích của tôi là viết mã rõ ràng vẫn chưa phân phối, nhưng những người khác đã đề xuất mã không cần thiết.

Tất nhiên, tất cả điều này áp dụng cho các đối tượng triển khai IDisposable. Đúng là GC sẽ chăm sóc hầu hết mọi thứ khác mà không có bất kỳ hành động rõ ràng nào về phía bạn, nhưng nó đáng đọc một chút về sự tinh tế của hành vi GC (tôi quá mệt mỏi khi nghĩ đến các chi tiết ngay bây giờ) để biết khi nào để xử lý các đối tượng một cách rõ ràng và quan trọng hơn là khi nào cần triển khai IDispose. Có rất nhiều bài viết hay về interwebs về vấn đề này.

Và như đã nói ở trên, việc sử dụng (..) {...} là bạn của bạn cho những người triển khai IDisposable.

+0

Bạn không chắc chắn lý do tại sao bạn đã bỏ phiếu ở đây. +1 từ tôi. –

6

Lý do bạn nên luôn gọi Dispose() trên bất kỳ loại nào triển khai IDisposable, là nó thường được sử dụng để biểu thị rằng loại mua lại tài nguyên không được quản lý. Điều đặc biệt quan trọng là chúng được giải phóng, và càng sớm càng tốt. Như những người khác đã đề cập, using là cách được ưu tiên để thực hiện việc này.

25

Vứt bỏ vật thể ngay khi bạn đã hoàn thành nó. Các đối tượng dùng một lần đại diện cho các đối tượng đang nắm giữ một tài nguyên có giá trị mà CLR không thực sự nhận thức được. Do đó GC cũng không biết các tài nguyên và không thể đưa ra các quyết định thông minh khi cần thu thập một đối tượng dùng một lần và do đó giải phóng tài nguyên cơ bản.

Cuối cùng GC sẽ cảm thấy áp lực bộ nhớ và thu thập đối tượng của bạn bằng sự trùng hợp ngẫu nhiên (không có gì khác).Nếu bạn không vứt bỏ các đối tượng theo cách xác định thì hoàn toàn có thể nhập trạng thái bị bỏ đói tài nguyên với hầu như không có áp lực bộ nhớ.

Ví dụ nhanh về cách điều này có thể xảy ra. Cho phép suy nghĩ của các nguồn tài nguyên cơ bản như Win32 xử lý. Đây là rất hữu hạn và khá nhỏ. Bạn chạy một hoạt động tạo ra rất nhiều đối tượng Foo. Các đối tượng Foo thực hiện IDisposable và chịu trách nhiệm tạo và xử lý một trình xử lý Win32. Chúng không được giải phóng thủ công và bởi một quirk khác biệt biến nó thành heap Gen2. Heap này được giải phóng khá thường xuyên. Qua thời gian đủ Foo trường hợp làm cho nó vào heap Gen2 để mất tất cả các tay cầm có sẵn. Các đối tượng Foo mới do đó không thể được tạo bất kể bộ nhớ đang được sử dụng bao nhiêu.

Trong thực tế để giải phóng các tay cầm, nó sẽ mất một số lượng khá lớn của bộ nhớ được phân bổ trong một hoạt động duy nhất để cung cấp đủ áp lực để giải phóng các trường hợp.

+0

System.Drawing lớp học không thông báo cho GC áp lực bộ nhớ đúng, do đó, họ không được ưu tiên để xử lý như họ cần (nó thấy một đối tượng 80mb là 1k hoặc ít hơn) –

1

Nếu đối tượng được triển khai IDisposable, rất có khả năng nó đang nắm giữ tài nguyên không được quản lý. Quy tắc của ngón tay cái, do đó, sẽ được gọi là Vứt bỏ thời điểm bạn đang thực hiện với các đối tượng, hoặc trực tiếp hoặc thông qua một khối sử dụng. Đừng dựa vào GC, vì đó là những gì IDisposable dành cho việc phát hành tài nguyên xác định.

0

Không, bạn có thể thoát khỏi bằng cách gọi Dispose trong trường hợp bạn không có tài nguyên không được quản lý. Nhưng nếu lớp của bạn đang nắm giữ một tài nguyên không được quản lý nói, một tệp tạm thời cần được xóa, thì bạn sẽ phải gọi rõ ràng là Vứt bỏ.

Bạn có thể tránh gọi Dispose bằng cách viết mã giải phóng của bạn trong phương thức Finalize nhưng sau đó bạn phụ thuộc vào Garbage Collector vì bạn không bao giờ chắc chắn hơn khi Garbage collector sẽ hoàn thành đối tượng của bạn. Để an toàn, nếu bạn đang thiết kế một lớp có chứa tài nguyên không được quản lý, bạn có thể viết cùng một mã giải phóng đối tượng trong cả phương thức Vứt bỏ và Hoàn thành nhưng nếu bạn làm như vậy, hãy luôn sử dụng SuppressFinalize() trong phương thức vứt bỏ của bạn bởi vì nó sẽ ngăn chặn phương thức Finalize() được gọi nếu đối tượng của bạn đã có trong Hàng đợi cuối cùng.

+0

Trên thực tế, phương pháp perfered không phải là để lặp lại các mã trong phương thức hoàn thiện của bạn và loại bỏ emthod, nhưng để thực hiện chi tiết trong liên kết này http://msdn.microsoft.com/en-us/library/b1yfkh5e(VS.71).aspx – Sekhat

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