Chính xác thì tài nguyên không được quản lý là gì?


159

Tôi muốn biết về tài nguyên không được quản lý. Bất cứ ai có thể xin vui lòng cho tôi một ý tưởng cơ bản?


Cũng xem trang này, đưa ra một lời giải thích và mẫu tuyệt vời cho việc sử dụng IDis Dùng đúng cách và cách đưa tài nguyên không được quản lý vào tài khoản: stackoverflow.com/questions/538060/
Kyle Baran

Câu trả lời:


177

Tài nguyên được quản lý về cơ bản có nghĩa là "bộ nhớ được quản lý" được quản lý bởi trình thu gom rác. Khi bạn không còn bất kỳ tham chiếu nào đến một đối tượng được quản lý (sử dụng bộ nhớ được quản lý), trình thu gom rác sẽ (cuối cùng) sẽ giải phóng bộ nhớ đó cho bạn.

Tài nguyên không được quản lý là tất cả mọi thứ mà người thu gom rác không biết đến. Ví dụ:

  • Mở tập tin
  • Mở kết nối mạng
  • Bộ nhớ không được quản lý
  • Trong XNA: bộ đệm đỉnh, bộ đệm chỉ mục, kết cấu, v.v.

Thông thường bạn muốn giải phóng những tài nguyên không được quản lý đó trước khi bạn mất tất cả các tài liệu tham khảo mà bạn có cho đối tượng quản lý chúng. Bạn làm điều này bằng cách gọi Disposevào đối tượng đó hoặc (trong C #) bằng cách sử dụng usingcâu lệnh sẽ xử lý việc gọi Disposecho bạn.

Nếu bạn bỏ qua Disposechính xác các tài nguyên không được quản lý của mình, trình thu gom rác cuối cùng sẽ xử lý nó cho bạn khi đối tượng chứa tài nguyên đó là rác được thu thập (đây là "quyết toán"). Nhưng vì người thu gom rác không biết về các tài nguyên không được quản lý, nên nó không thể cho biết mức độ cần thiết để giải phóng chúng - vì vậy chương trình của bạn có thể hoạt động kém hoặc hết tài nguyên hoàn toàn.

Nếu bạn tự thực hiện một lớp xử lý các tài nguyên không được quản lý, thì việc bạn thực hiện DisposeFinalizechính xác là tùy thuộc vào bạn .


7
Kết nối cơ sở dữ liệu mở thuộc loại nào? Quản lý / Không được quản lý?
Deviprasad Das

8
+1 Các câu trả lời khác bỏ lỡ điểm quan trọng mà bạn đang gọi Vứt bỏ trên một đối tượng được quản lý , bên trong xử lý việc giải phóng tài nguyên không được quản lý mà nó bao bọc (ví dụ: xử lý tệp, GDI + bitmap, ...) và nếu bạn truy cập trực tiếp vào các tài nguyên không được quản lý ( PInvoke, v.v.) bạn cần xử lý việc đó.
Ian Mercer

2
@Dev: Không được quản lý - vì GC không biết về nó (giả sử bạn không sử dụng một số cơ sở dữ liệu trong bộ nhớ được quản lý giả định). Nhưng bản thân đối tượng kết nối có thể không chứa tài nguyên không được quản lý. Có lẽ kết nối cơ sở dữ liệu sử dụng tệp mở hoặc kết nối mạng ở đâu đó - nhưng có thể một đối tượng khác (không phải đối tượng kết nối) đang xử lý tài nguyên không được quản lý đó (có lẽ thư viện cơ sở dữ liệu của bạn lưu trữ các kết nối). Kiểm tra tài liệu và xem nơi nó yêu cầu bạn gọi Disposehoặc sử dụng using.
Andrew Russell

11
Tôi có một nhận xét / câu hỏi cơ bản về vấn đề này, tôi có thể liên hệ một đối tượng là được quản lý / không được quản lý chỉ bằng loại, ví dụ: chuỗi được quản lý, Dataset không được quản lý (đó là lý do tại sao nó có phương thức Dispose ()) , Các kết nối cơ sở dữ liệu không được quản lý (vì chúng đã loại bỏ), v.v ... Vậy có phải là giả định, nếu nó có phương thức "Vứt bỏ ()" thì nó không được quản lý? Thêm vào đó, một đối tượng XmlDocument sẽ là gì? Cảm ơn
ganders

15
@ganders Đó là một quy tắc tốt. Mặc dù lưu ý rằng tất cả các thể hiện của lớp C # đều là các đối tượng được quản lý. Nếu một thể hiện của một lớp có thể chứa các tài nguyên không được quản lý, thì lớp đó sẽ thực hiện IDisposable. Nếu một lớp không thực hiện IDisposable, sau đó bạn nên vứt bỏ các trường hợp mà lớp với usinghoặc Dispose()khi bạn đang thực hiện với họ. Dựa trên điều này, converse của bạn giữ: Nếu một lớp thực hiện IDisposable, thì nó có thể chứa các tài nguyên không được quản lý trong nội bộ.
Andrew Russell

56

Một số người dùng xếp hạng các tệp đang mở, kết nối db, bộ nhớ được phân bổ, bitmap, luồng tệp, v.v. trong số các tài nguyên được quản lý, những người khác trong số không được quản lý. Vì vậy, họ được quản lý hoặc không được quản lý?

Ý kiến ​​của tôi là, phản hồi phức tạp hơn: Khi bạn mở tệp trong .NET, bạn có thể sử dụng một số lớp .NET tích hợp System.IO.File, FileStream hoặc một cái gì đó khác. Bởi vì nó là một lớp .NET bình thường, nó được quản lý. Nhưng nó là một trình bao bọc, bên trong thực hiện "công việc bẩn thỉu" (giao tiếp với hệ điều hành bằng cách sử dụng các dll Win32, gọi các hàm cấp thấp hoặc thậm chí các hướng dẫn trình biên dịch) thực sự mở tệp. Và đây là, những gì .NET không biết, không được quản lý. Nhưng có lẽ bạn có thể tự mở tệp bằng cách sử dụng hướng dẫn trình biên dịch và bỏ qua các chức năng tệp .NET. Sau đó, xử lý và các tập tin mở là tài nguyên không được quản lý.

Tương tự với DB: Nếu bạn sử dụng một số cụm DB, bạn có các lớp như DbConnection, v.v., chúng được biết đến với .NET và được quản lý. Nhưng họ bọc "công việc bẩn thỉu", không được quản lý (phân bổ bộ nhớ trên máy chủ, thiết lập kết nối với nó, ...). Nếu bạn không sử dụng lớp trình bao bọc này và tự mở một số ổ cắm mạng và liên lạc với cơ sở dữ liệu lạ của riêng bạn bằng một số lệnh, thì nó không được quản lý.

Các lớp trình bao bọc này (Tệp, DbConnection, v.v.) được quản lý, nhưng chúng bên trong sử dụng các tài nguyên không được quản lý theo cùng một cách như bạn, nếu bạn không sử dụng trình bao bọc và tự mình thực hiện "công việc bẩn". Và do đó, các hàm bao này thực hiện các mẫu Vứt bỏ / Hoàn thiện. Trách nhiệm của họ là cho phép lập trình viên giải phóng các tài nguyên không được quản lý khi không cần trình bao bọc nữa và giải phóng chúng khi trình bao bọc được thu gom rác. Trình bao bọc sẽ là rác chính xác được thu thập bởi người thu gom rác, nhưng các tài nguyên không được quản lý bên trong sẽ được thu thập bằng cách sử dụng mẫu Vứt bỏ / Hoàn thiện.

Nếu bạn không sử dụng các lớp trình bao bọc .NET hoặc bên thứ ba tích hợp và mở các tệp theo một số hướng dẫn trình biên dịch, v.v. trong lớp của bạn, các tệp mở này không được quản lý và bạn PHẢI triển khai mẫu xử lý / hoàn thiện. Nếu bạn không, sẽ có rò rỉ bộ nhớ, tài nguyên bị khóa vĩnh viễn, vv ngay cả khi bạn không sử dụng nó nữa (hoàn tất thao tác tệp) hoặc thậm chí sau khi ứng dụng của bạn chấm dứt.

Nhưng trách nhiệm của bạn cũng là khi sử dụng các hàm bao này. Đối với những người triển khai xử lý / hoàn thiện (bạn nhận ra họ, họ thực hiện IDis Dùng một lần), cũng triển khai mô hình xử lý / hoàn thiện của bạn và loại bỏ ngay cả các trình bao bọc này hoặc cung cấp cho họ tín hiệu để giải phóng tài nguyên không được quản lý của họ. Nếu bạn không, tài nguyên sẽ có sau một thời gian không xác định được phát hành, nhưng bạn có thể phát hành ngay lập tức (đóng tệp ngay lập tức và không để mở và bị chặn trong vài phút / giờ ngẫu nhiên). Vì vậy, trong phương thức Vứt bỏ lớp của bạn, bạn gọi các phương thức Vứt bỏ tất cả các hàm bao được sử dụng của bạn.


1
Tốt về sự rõ ràng bổ sung trênunmanaged vs managed resources
bây giờ người không được đặt tên.

thx cho câu trả lời của bạn. Những lớp nào được khuyến nghị mà chúng ta thực sự gọi là Dispose?
BKSpurgeon

2
Cái này đơn giản. Trên mỗi lớp mà bạn sử dụng, bạn phải xác minh xem nó có thực hiện giao diện IDis Dùng không. Nếu có, thì nếu bạn sử dụng lớp đó trong một phương thức (ví dụ: mở tệp, lưu trữ văn bản, đóng tệp), bạn có thể sử dụng mẫu đó bằng cách sử dụng () {}, tự động gọi cho bạn. Nếu bạn sử dụng lớp đó trong nhiều phương thức hơn (ví dụ: lớp của bạn chứa Tệp, trong hàm tạo, nó sẽ mở tệp, sau đó một số phương thức thêm một số nhật ký ...), thì bạn phải triển khai giao diện IDis Dùng cho lớp của mình, triển khai mẫu Loại bỏ / Hoàn tất và xử lý đúng đối tượng của lớp đó.
Martas

1
"... một số lớp .NET tích hợp System.IO.File, FileStream hoặc một cái gì đó khác. Bởi vì nó là một lớp .NET bình thường, nên nó được quản lý." Với sự tôn trọng, điều này là sai và sai lệch. Họ không được quản lý . Nếu chúng được quản lý, thì bạn có thể phân bổ các lớp này và hy vọng trình thu gom rác sẽ xử lý hoàn toàn việc phân bổ tất cả các tài nguyên theo kiểu xác định. Tuy nhiên, điều này sẽ dẫn đến việc xử lý tệp và các tài nguyên không được quản lý bị khóa và giữ lâu hơn mức cần thiết vì trình thu gom rác sẽ không phân bổ lớp và không hoàn thành trong một thời gian rất dài.
AaronLS

1
@AaronLS trong nhận xét của bạn, bạn đã nói về "FileStream" bằng cách coi nó là không được quản lý nhưng không, mặc dù bên trong nó sử dụng các tài nguyên không được quản lý để thực hiện công việc của mình. Trong thế giới được quản lý, Microsoft đã ẩn giấu rất nhiều thứ không được quản lý từ bạn bằng cách triển khai mô hình xử lý. Mã được quản lý không có nghĩa là nó không sử dụng tài nguyên không được quản lý. Tuy nhiên, Microsoft đã thực hiện tốt việc triển khai IDis Dùng trên các loại đối tượng đó. Điều này được chứng minh bằng thực tế rằng nó thực hiện IDis Dùng một lần. Đối với bằng chứng đó, chúng ta nên coi nó là một đối tượng được quản lý.
Malik Khalil

12

Các tài nguyên không được quản lý là những tài nguyên chạy bên ngoài thời gian chạy .NET (CLR) (còn gọi là mã không phải .NET.) Ví dụ: một cuộc gọi đến một DLL trong API Win32 hoặc một cuộc gọi đến một văn bản được viết bằng C ++.


6

Một "tài nguyên không được quản lý" không phải là một thứ, mà là một trách nhiệm. Nếu một đối tượng sở hữu một tài nguyên không được quản lý, điều đó có nghĩa là (1) một thực thể bên ngoài nó đã bị thao túng theo cách có thể gây ra vấn đề nếu không được dọn sạch và (2) đối tượng có thông tin cần thiết để thực hiện việc dọn dẹp đó và chịu trách nhiệm để làm điều đó

Mặc dù nhiều loại tài nguyên không được quản lý có liên quan rất mạnh với nhiều loại thực thể hệ điều hành khác nhau (tệp, xử lý GDI, khối bộ nhớ được phân bổ, v.v.), không có loại thực thể nào được chia sẻ bởi tất cả chúng ngoài trách nhiệm của chúng dọn dẹp. Thông thường, nếu một đối tượng có trách nhiệm thực hiện việc dọn dẹp, nó sẽ có một phương thức Vứt bỏ để hướng dẫn nó thực hiện tất cả việc dọn dẹp mà nó chịu trách nhiệm.

Trong một số trường hợp, các đối tượng sẽ thực hiện trợ cấp cho khả năng chúng có thể bị bỏ rơi mà không có ai gọi là Vứt bỏ trước. GC cho phép các đối tượng yêu cầu thông báo rằng họ đã bị bỏ rơi (bằng cách gọi một thói quen gọi là Hoàn thiện) và các đối tượng có thể sử dụng thông báo này để tự thực hiện việc dọn dẹp.

Thật không may, các thuật ngữ như "tài nguyên được quản lý" và "tài nguyên không được quản lý", không may, được sử dụng bởi những người khác nhau có nghĩa là những thứ khác nhau; thẳng thắn nghĩ rằng sẽ hữu ích hơn khi nghĩ về các đối tượng là không có trách nhiệm dọn dẹp, có trách nhiệm dọn dẹp sẽ chỉ được quan tâm nếu Dispose được gọi, hoặc có trách nhiệm dọn dẹp cần được chăm sóc thông qua Vứt bỏ, nhưng có thể cũng được chăm sóc bởi Finalize.


5

Sự khác biệt cơ bản giữa tài nguyên được quản lý và không được quản lý là trình thu gom rác biết về tất cả các tài nguyên được quản lý, đến một lúc nào đó, GC sẽ xuất hiện và dọn sạch tất cả bộ nhớ và tài nguyên liên quan đến một đối tượng được quản lý. GC không biết về các tài nguyên không được quản lý, chẳng hạn như tệp, luồng và xử lý, vì vậy nếu bạn không dọn sạch chúng trong mã của mình thì bạn sẽ bị rò rỉ bộ nhớ và tài nguyên bị khóa.

Bị đánh cắp từ đây , hãy đọc toàn bộ bài viết.


2

Bất kỳ tài nguyên nào mà bộ nhớ được phân bổ trong heap được quản lý .NET đều là tài nguyên được quản lý. CLR hoàn toàn nhận thức được loại bộ nhớ này và sẽ làm mọi thứ để đảm bảo rằng nó không bị mồ côi. Bất cứ điều gì khác là không được quản lý. Ví dụ, xen kẽ với COM, có thể tạo các đối tượng trong không gian bộ nhớ, nhưng CLR sẽ không chăm sóc nó. Trong trường hợp này, đối tượng được quản lý thực hiện các cuộc gọi trên toàn bộ biên giới được quản lý phải chịu trách nhiệm cho bất kỳ điều gì ngoài nó.


0

Trước tiên chúng ta hãy hiểu cách các chương trình VB6 hoặc C ++ (ứng dụng Non Dotnet) được sử dụng để thực thi. Chúng tôi biết rằng máy tính chỉ hiểu mã cấp độ máy. Mã cấp độ máy cũng được gọi là mã gốc hoặc mã nhị phân. Vì vậy, khi chúng tôi thực hiện chương trình VB6 hoặc C ++, trình biên dịch ngôn ngữ tương ứng, biên dịch mã nguồn ngôn ngữ tương ứng thành mã gốc, sau đó có thể được hiểu bởi hệ điều hành và phần cứng bên dưới.

Mã riêng (Mã không được quản lý) là cụ thể (nguyên gốc) cho hệ điều hành mà nó được tạo. Nếu bạn lấy mã gốc được biên dịch này và cố gắng chạy trên một hệ điều hành khác, nó sẽ thất bại. Vì vậy, vấn đề với phong cách thực hiện chương trình này là, nó không thể di chuyển từ nền tảng này sang nền tảng khác.

Bây giờ chúng ta hãy hiểu, làm thế nào một chương trình .Net thực thi. Sử dụng dotnet chúng ta có thể tạo các loại ứng dụng khác nhau. Một số loại ứng dụng .NET phổ biến bao gồm Web, Windows, Console và Ứng dụng di động. Không phân biệt loại ứng dụng, khi bạn thực thi bất kỳ ứng dụng .NET nào, điều sau đây xảy ra

  1. Ứng dụng .NET được biên dịch sang ngôn ngữ Trung cấp (IL). IL cũng được gọi là ngôn ngữ trung gian chung (CIL) và ngôn ngữ trung gian Microsoft (MSIL). Cả hai ứng dụng .NET và không .NET đều tạo ra một hội đồng. Các hội đồng có phần mở rộng là .DLL hoặc .EXE. Ví dụ: nếu bạn biên dịch một cửa sổ hoặc ứng dụng Console, bạn sẽ nhận được một .EXE, trong đó khi chúng tôi biên dịch một dự án thư viện web hoặc Class, chúng tôi nhận được một .DLL. Sự khác biệt giữa tập hợp .NET và NON .NET là ở chỗ, hội DOTNET có định dạng ngôn ngữ trung gian trong đó tập hợp NON DOTNET ở định dạng mã gốc.

  2. Các ứng dụng NON DOTNET có thể chạy trực tiếp trên hệ điều hành, trong đó các ứng dụng DOTNET chạy trên môi trường ảo được gọi là Thời gian chạy ngôn ngữ chung (CLR). CLR chứa một thành phần được gọi là Trình biên dịch đúng lúc (JIT), sẽ chuyển đổi ngôn ngữ Trung gian thành mã gốc mà hệ điều hành cơ bản có thể hiểu được.

Vì vậy, trong .NET, việc thực thi ứng dụng bao gồm 2 bước 1. Trình biên dịch ngôn ngữ, biên dịch Mã nguồn thành Ngôn ngữ trung gian (IL) 2. Trình biên dịch JIT trong CLR chuyển đổi, IL thành mã gốc có thể chạy trên hệ điều hành cơ bản .

Vì, một cụm .NET có định dạng Ngôn ngữ Intermedaite chứ không phải mã gốc, các cụm .NET có thể di chuyển tới bất kỳ nền tảng nào, miễn là nền tảng đích có Thời gian chạy ngôn ngữ chung (CLR). CLR của nền tảng đích chuyển đổi Ngôn ngữ Intermedaite thành mã gốc mà hệ điều hành cơ bản có thể hiểu được. Languge trung gian cũng được gọi là mã được quản lý. Điều này là do CLR quản lý mã chạy bên trong nó. Ví dụ, trong một chương trình VB6, nhà phát triển chịu trách nhiệm phân bổ lại bộ nhớ mà một đối tượng sử dụng. Nếu một lập trình viên quên phân bổ bộ nhớ, chúng ta có thể gặp khó khăn trong việc loại bỏ các ngoại lệ của bộ nhớ. Mặt khác, một lập trình viên .NET không cần phải lo lắng về việc phân bổ lại bộ nhớ mà một đối tượng sử dụng. Quản lý bộ nhớ tự động, còn được gọi là bộ sưu tập snapage được cung cấp bởi CLR. Riêng biệt, từ bộ sưu tập rác, có một số lợi ích khác được cung cấp bởi CLR, mà chúng ta sẽ thảo luận trong phần sau. Vì, CLR đang quản lý và thực thi Ngôn ngữ trung gian, nên nó (IL) còn được gọi là mã được quản lý.

.NET hỗ trợ các ngôn ngữ lập trình khác nhau như C #, VB, J # và C ++. C #, VB và J # chỉ có thể tạo mã được quản lý (IL), trong đó C ++ có thể tạo cả mã được quản lý (IL) và mã không được quản lý (mã gốc).

Mã riêng không được lưu trữ vĩnh viễn ở bất cứ đâu, sau khi chúng tôi đóng chương trình, mã gốc sẽ bị loại bỏ. Khi chúng ta thực hiện lại chương trình, mã gốc sẽ được tạo lại.

Chương trình .NET tương tự như thực hiện chương trình java. Trong java, chúng ta có mã byte và JVM (Máy ảo Java), trong đó như trong .NET, chúng ta có Ngôn ngữ trung gian và CLR (Thời gian chạy ngôn ngữ chung)

Điều này được cung cấp từ liên kết này - Ông là một gia sư tuyệt vời. http://csharp-video-tutorials.blogspot.in/2012/07/net-program-execut-part-1.html

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.