2010-06-29 30 views
5

Khi sử dụng SqlConnection, điều quan trọng là phải luôn đóng nó khi được sử dụng - hoặc bằng .Close() hoặc đặt SqlConnection trong "đang sử dụng". Thật không may, mọi người, kể cả bản thân tôi, có xu hướng quên điều đó và đây là nơi những người thu gom rác cứu tôi trong một thời gian cho đến khi tôi quên đóng kết nối quá nhiều lần hoặc số người sử dụng ứng dụng tăng lên.Phát hiện xem bộ thu gom rác đã được gọi (.Net)

Tôi muốn biết, nếu có thể, làm cách nào để phát hiện xem bộ thu gom rác có xử lý SqlConnection hay không bởi vì nó cho rằng nó không được sử dụng nữa hoặc nếu SqlConnection đã đóng đúng cách.

Một cách khác có thể kế thừa SqlConnection và đặt bộ đếm thời gian trên bộ khởi tạo của nó và kiểm tra xem mất bao lâu để ngắt kết nối khi loại bỏ lớp. Tôi không thực sự thích hẹn giờ nhưng ý tưởng chỉ xuất hiện khi viết điều này.

Có thể có cách thứ ba và thậm chí thông minh hơn cho tất cả điều này ... Bạn sẽ đề xuất điều gì?

+0

'bằng cách .Close() hoặc đặt SqlConnection trong một "sử dụng" '** NO NO NO! ** .Close() là _not_ đủ tốt bởi chính nó. Đó là toàn bộ điểm của cấu trúc 'using': quá nhiều người cũng quên rằng bạn .Close() _must_ nằm trong một khối cuối cùng. –

Trả lời

2

Một quy tắc chung: "Nếu bạn phải suy nghĩ về bộ thu gom rác, có thể bạn đang làm điều gì sai". (Tất nhiên, có những ngón tay cái khác ...)

Dường như với tôi đảm bảo rằng các kết nối được đóng kín hoặc thông qua các khối usingfinally là tuyến đường tốt nhất.

Rõ ràng, bạn đã hiểu những kỹ thuật này ... do đó, có thể một mã thông qua một lần và một trình tái cấu trúc có thể là tất cả những gì bạn cần.

0

Nếu bạn quên vứt bỏ, đối tượng sẽ được hoàn thành. Không có cách nào để kiểm soát thời gian mà điều này xảy ra, và cũng không có cách nào để bạn biết nếu một đối tượng được hoàn thành. Một thread riêng biệt phải được tạo ra để hoàn thành các đối tượng, do đó, nó làm chậm ứng dụng của bạn xuống. Đó là lý do tại sao bạn muốn vứt bỏ. Trong tất cả các lớp trong khung công tác thực hiện IDisposable, một cuộc gọi đến GC.SuppressFinalize được thực hiện, vì vậy đối tượng không được hoàn thành.

Không có cách nào để bạn kiểm soát hành vi này. Nếu đối tượng của bạn không được sử dụng nữa, nó sẽ tự động được thu thập. Tất cả những gì bạn có thể làm để ngăn chặn điều này, được gọi là GC.SuppressFinalize, nhưng tôi sẽ không khuyên bạn nên, bởi vì nếu bạn quên, bạn sẽ bị vất vả cho cuộc sống.

Bạn có thể tạo lớp trình bao bọc (không phải lớp con), mà bạn sử dụng trong mã cung cấp một vài phương pháp đơn giản luôn gọi là Vứt bỏ. Nếu không, chỉ cần kiểm tra thực sự tốt.

+0

Tôi muốn nói "thường sẽ được hoàn thành". Các tình huống có thể dễ dàng phát sinh khi không có 'Vứt bỏ' một đối tượng được gắn với một thứ gì đó của thời gian tĩnh sẽ ngăn chặn đối tượng đó, * hoặc bất kỳ thứ gì mà nó chứa tham chiếu trực tiếp hoặc gián tiếp *, từ * bao giờ * trở thành đủ điều kiện để thu thập rác. – supercat

4

Vì SqlConnection được niêm phong, bạn sẽ không thể kế thừa từ nó. (Và tôi không nghĩ rằng đó là một ý tưởng tốt để làm như vậy - Nếu nó có thể, bạn có lẽ nên thêm mã của bạn trong Dispose (false), bởi vì đó là những gì finalizer gọi).

Tốt hơn là phát hiện các loại sự cố này bằng cách sử dụng công cụ phân tích mã tĩnh, công cụ này có khả năng phát hiện tất cả các địa điểm trong mã của bạn nơi bạn quên bỏ kết nối. Có một cái được xây dựng trong in Visual Studio hoặc bạn có thể sử dụng FxCop.

Để giúp bạn không quên xử lý các kết nối, nó là một ý tưởng tốt để:

  • Giữ tất cả các mã kết nối DB trong một lớp/lắp ráp/mô-đun, vì vậy nó không được phân tán thông qua các dự án.
  • Có các phương thức tiện ích để thực hiện các lệnh SQL và trả về kết quả; vì vậy bạn không tạo SQLConnection nhiều nơi hơn bạn cần.
  • Hãy nhớ sử dụng số C# using construct.
+2

+1 cách tốt nhất để tiếp cận điều này là lấy nguyên nhân gốc rễ và Vứt bỏ các kết nối. –

1

Nếu ứng dụng của bạn đang sử dụng kết nối SQL Pooling (mặc định) nó sẽ không quan trọng vì các kết nối được sử dụng lại và không đóng khi bạn gọi .Đóng() hoặc để lại khối using() {} .

http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx

Để trả lời câu hỏi của bạn, tôi không tin rằng có một sự kiện cho bộ sưu tập GC, tuy nhiên nó sẽ không thành vấn đề nếu có, bởi vì bạn sẽ không bao giờ biết nếu GC đã chọn để tái chế đối tượng của bạn về bộ sưu tập vượt qua (không phải tất cả các đối tượng được làm sạch vì thuật toán thế hệ).

Tôi cũng sẽ tránh các nỗ lực sử dụng bộ tính giờ và "kiểm tra" vì bạn có thể sẽ giữ tham chiếu đến đối tượng và ngăn không cho nó bị xử lý.

+0

Nhưng nó không quan trọng kể từ khi các kết nối không được đóng lại thì chúng không được trả lại hồ bơi để chúng không được tái sử dụng ngay lập tức. Điều này có thể làm cạn kiệt hồ bơi kết nối của bạn hoặc tiêu thụ các tài nguyên có giá trị gây ra sự cố. –

+1

Đồng ý, nhưng vấn đề là OP muốn biết "khi nào" một vụ thu gom rác xảy ra. Quan điểm của tôi là bộ sưu tập các kết nối sql sẽ không xảy ra với tổng hợp. Giải pháp duy nhất là thực sự sửa chữa và đảm bảo .Close() đang được gọi, không dựa vào sự kiện thu thập GC hoặc kiểm tra hẹn giờ. – David

0

Trước tiên, nếu bạn thậm chí đang cân nhắc việc sử dụng GC, bạn đã gặp sự cố nghiêm trọng ở đâu đó. Tôi đề nghị cách tốt nhất để đảm bảo các cuộc gọi mã của bạn Close là để kiểm tra đơn vị mã của bạn bằng cách sử dụng các kỹ thuật như mocking. Nếu kiểm tra đơn vị của bạn chỉ ra rằng Close đã được gọi, mã của bạn là chính xác và bạn không phải làm bất cứ điều gì không cần thiết nguy hiểm như mucking xung quanh với Garbage Collector.

Thứ hai, nếu bạn vẫn khăng khăng tiến hành tuyến kiểm tra thời gian chạy, chỉ chỉ điều mà bạn thậm chí nên xem xét là đang gắn sự kiện StateChangeSqlConnection. Điều đó sẽ kích hoạt nếu ConnectionState thay đổi từ Mở sang đóng, ví dụ.

1

Tôi không quen thuộc với bộ thu gom rác và không biết nếu có cách trực tiếp để lấy thông tin nhưng ý tưởng đầu tiên của tôi là thông tin sau.

Chỉ cần tạo weak reference cho đối tượng giả. Nếu bạn nhìn vào tài liệu tham khảo yếu sau này và đối tượng không còn là alive, bạn có thể giả định rằng một bộ sưu tập rác đã xảy ra.

(. Câu trả lời này chỉ áp dụng cho việc phát hiện thu gom rác chạy tôi hoàn toàn bỏ qua lý do để làm điều này - có chiến lược tốt hơn để đối phó với rò rỉ tài nguyên.)

+0

Đó là toàn bộ vấn đề, bạn cần phải vứt bỏ để ngăn chặn việc hoàn thiện. Nếu bạn chỉ cần giữ một ref yếu và kiểm tra xem nếu nó đã xảy ra, bạn đã quá muộn. (Bộ sưu tập rác sau khi hoàn thành). –

+0

Có tất nhiên. Như đã nói trong câu cuối cùng tôi chỉ muốn trả lời "Phát hiện nếu bộ thu gom rác đã được gọi".Bạn không nên viết mã để rò rỉ tài nguyên ngay từ đầu. Và điều này có thể tránh được hiệu quả bằng cách thực hiện phân tích tĩnh và hồ sơ thời gian chạy. –