2009-01-29 30 views
24

Tôi đã đọc số MSDN article about how to implement IDisposable và tôi không chắc chắn về sự khác biệt giữa tài nguyên được quản lý và nguồn gốc được trích dẫn trong bài viết.Sự khác nhau giữa tài nguyên được quản lý và nguồn gốc khi xử lý là gì? (.NET)

Tôi có một lớp học phải thải bỏ 2 trường của nó khi nó được xử lý. Tôi có nên coi chúng là Được quản lý (chỉ xử lý khi vứt bỏ = true) hoặc tài nguyên Gốc không?

Trả lời

18

Tài nguyên được quản lý là một loại được quản lý khác, thực hiện IDisposable. Bạn cần gọi số Dispose() trên bất kỳ loại nào khác IDisposable loại bạn sử dụng. nguồn lực bản địa là bất cứ điều gì bên ngoài thế giới được quản lý như Windows bản địa xử lý, vv


EDIT: trả lời cho câu hỏi bằng nhận xét (quá dài cho bình luận)

Không, đó chỉ là một kiểu quản lý. Loại được xây dựng chính xác, không triển khai IDisposable sẽ được người thu gom rác xử lý và bạn không phải làm bất kỳ điều gì khác. Nếu loại của bạn sử dụng tài nguyên gốc trực tiếp (ví dụ: bằng cách gọi thư viện Win32), bạn phải triển khai IDisposable về loại của bạn và xử lý (các) tài nguyên theo phương thức Dispose. Nếu loại của bạn sử dụng tài nguyên gốc được đóng gói bởi một loại khác triển khai IDisposable, bạn phải gọi Dispose() trên các trường hợp thuộc loại này theo phương thức Dispose thuộc loại của bạn.

+0

Vì vậy, là một loại quản lý mà không thực hiện IDisposable một nguồn lực không được quản lý? Có lẽ tôi đang bị nhầm lẫn bởi các loại câu thơ tài nguyên ... –

+0

@Yooder: Làm thế nào bạn có thể có một tài nguyên được quản lý mà không được đại diện bởi một loại? –

+0

@LarryFix: Những người khác nhau sử dụng thuật ngữ khác nhau, nhưng tôi sẽ nói rằng một đối tượng không hỏi * cái gì khác * để làm điều gì đó thay mặt nó, cho đến khi có thông báo mới, và gây tổn hại cho người khác, không giữ * bất kỳ * tài nguyên. – supercat

21

Để thêm một chút để câu trả lời của Brian, và nhận xét của bạn/câu hỏi:

Sự khác biệt giữa một nguồn tài nguyên được quản lý/Switch là Collector rác là nhận thức của các nguồn tài nguyên được quản lý và không nhận thức được các nguồn lực không được quản lý. Tôi biết rằng câu trả lời không phải là rất cụ thể nhưng sự khác biệt là rất lớn.

Để giúp vẽ đường trên cát ở đây là phiên bản ngắn (và có lẽ thủng với lỗi nhỏ) của GC chạy như thế nào và dọn dẹp bộ nhớ:

thu

Rác là nhận thức của tất cả các đối tượng được quản lý nhưng khi rác bộ sưu tập chạy nó ban đầu không biết nếu bất kỳ đối tượng nhất định vẫn được sử dụng hoặc là sang trọng để được phát hành. Nó xác định có hay không nó có thể dọn dẹp một đối tượng bằng cách đánh dấu tất cả các đối tượng là rác, sau đó đi ngang từ gốc ứng dụng đến tất cả các đối tượng được tham chiếu. Mỗi đối tượng có mối quan hệ trở lại gốc (tham chiếu, trực tiếp hoặc gián tiếp) được đánh dấu là có thể truy cập và không còn được coi là rác. Sau khi GC chạy qua mọi đối tượng có thể truy cập, nó sẽ dọn sạch phần còn lại vì chúng không còn được sử dụng nữa.

Trong hầu hết các trường hợp làm việc với các đối tượng .NET framework, bạn có thể yên tâm rằng các đối tượng được quản lý (.NET cung cấp các trình bao bọc được quản lý gần như tất cả các tài nguyên không được quản lý để đảm bảo chúng được dọn dẹp đúng cách); các thành phần bên thứ ba khác móc vào API Win32 (hoặc các thành phần của bạn làm điều này) là các đối tượng có thể gây ra mối quan tâm.

Có một số đối tượng .NET có thể được coi là không được quản lý. Các thành phần của thư viện đồ họa là một ví dụ.

Hầu hết "rò rỉ bộ nhớ .NET" không thực sự bị rò rỉ bộ nhớ theo đúng nghĩa. Thông thường, chúng xuất hiện khi bạn nghĩ rằng bạn đã xóa một đối tượng khỏi sử dụng nhưng trên thực tế đối tượng vẫn có một số tham chiếu đến ứng dụng. Một ví dụ phổ biến là thêm eventhandlers (obj.SomeEvent + = OnSomeEvent -or- AddHandler obj.SomeEvent, AddressOf OnSomeEvent) và không loại bỏ chúng.

Những 'tham chiếu kéo dài' này về mặt kỹ thuật không rò rỉ bộ nhớ vì ứng dụng của bạn vẫn đang sử dụng kỹ thuật chúng; tuy nhiên nếu có đủ ứng dụng của bạn có thể bị ảnh hưởng nghiêm trọng về hiệu suất và có thể hiển thị các dấu hiệu của các vấn đề tài nguyên (OutOfMemoryExceptions, không thể đạt được xử lý cửa sổ, v.v.).

Tôi là một nhà phát triển .NET trung gian và không may biết về những vấn đề này trực tiếp. Tôi khuyên bạn nên chơi với ANTS Profiler để giúp làm quen với các tài liệu tham khảo kéo dài (có một phiên bản dùng thử miễn phí) hoặc nếu bạn muốn nghiên cứu nhiều hơn một chút bằng cách sử dụng WinDbg và SOS.DLL để xem xét vùng quản lý. Nếu bạn quyết định xem xét sau này, tôi khuyên bạn nên đọc blog của Tess Ferrandez; cô ấy có rất nhiều hướng dẫn tuyệt vời và lời khuyên về việc sử dụng Windbg hiệu quả

+3

Tôi thích câu trả lời của bạn.Sự khác biệt quan trọng nhất giữa các nguồn lực được quản lý và không được quản lý không phải là liệu chúng có tồn tại trong thế giới GC hay không, nhưng liệu GC có biết cách làm tất cả các dọn dẹp cần thiết nếu chúng bị bỏ rơi. Nếu không làm sạch một cái gì đó có thể làm giảm chức năng hệ thống, nhưng GC cấp 2 sẽ chăm sóc nó, đó là một tài nguyên được quản lý. Nếu không làm sạch một cái gì đó có thể làm giảm chức năng hệ thống, và thậm chí lặp đi lặp lại mức độ 2 GC sẽ không giúp đỡ, đó là một nguồn tài nguyên không được quản lý. – supercat

1

Câu trả lời ngắn gọn sẽ là bất cứ điều gì bạn đi sau lưng CLR (với hệ điều hành) để có được gọi là 'native'.

  • phân bổ bộ nhớ không được quản lý. Nếu bạn 'mới' lên một đoạn bộ nhớ trong một lớp được quản lý CantStayManaged, thì CantStayManaged chịu trách nhiệm giải phóng bộ nhớ này (tài nguyên).
  • xử lý các tập tin, đường ống, các sự kiện, cấu trúc đồng bộ, vv - như một quy luật ngón tay cái nếu bạn gọi WinAPIs để có được con trỏ/xử lý tới một tài nguyên, sau đó đó là những 'tài nguyên bản địa'

Bây giờ CantStayManaged có 2 thứ cần dọn dẹp trước khi nó đặt giá thầu.

  1. Được quản lý: Các trường thành viên và bất kỳ tài nguyên nào được phân bổ CLR. Điều này thường tương đương với việc gọi Dispose trên các đối tượng thành viên 'Dùng một lần' của bạn.
  2. Không được quản lý: tất cả những thứ cấp thấp lén lút mà chúng tôi kéo ra sau lưng.

Có 2 cách để dọn dẹp đối tượng có thể được kích hoạt ngay bây giờ.

  1. Vứt bỏ (đúng) trường hợp: Bạn được gọi là Vứt bỏ rõ ràng trên loại của bạn. Lập trình tốt.
  2. Vứt bỏ (sai) trường hợp: Bạn quên gọi Dispose, trong trường hợp đó finalizer nên kick vào và vẫn đảm bảo dọn dẹp thích hợp.

Trong cả hai trường hợp, các tài nguyên không được quản lý sẽ được giải phóng khác 'LỰA CHỌN!', 'THỜI TRANG!' et.all bề mặt. Nhưng bạn chỉ nên cố gắng dọn dẹp tài nguyên được quản lý trong trường hợp cũ của Dispose(). Trong trường hợp sau/finalizer - CLR có thể đã hoàn thành và thu thập một số thành viên của bạn, vì vậy bạn không nên truy cập chúng (CLR không đảm bảo một trật tự trong đó một đồ thị đối tượng được hoàn thành.) Do đó bạn tránh các vấn đề bảo vệ dọn dẹp quản lý của bạn với một kiểm tra if (AmIBeingCalledFromDispose) bảo vệ

HTH

+0

Trong khi tài nguyên gốc được tổ chức trực tiếp là tài nguyên không được quản lý, có thể có tài nguyên không được quản lý hoàn toàn trong mã được quản lý. Một đối tượng nắm giữ một "tài nguyên" là một đối tượng đã yêu cầu một cái gì đó khác để làm điều gì đó thay mặt cho nó, cho đến khi có thông báo mới, gây tổn hại tiềm năng cho người khác. Tài nguyên sẽ không được GC dọn sạch đúng cách nếu bị bỏ qua là tài nguyên không được quản lý. – supercat

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