2010-10-13 40 views
9

Tôi đang có một chút nhầm lẫn, có thể là câu hỏi này rất ngớ ngẩn.Quản lý bộ nhớ của thành phần không được quản lý theo CLR

bộ nhớ được phân bổ cho thành phần không được quản lý ở đâu?

Trong mã .net của tôi nếu tôi khởi tạo thành phần không được quản lý, nơi thành phần này sẽ được tải và bộ nhớ được cấp phát?

Làm thế nào CLR marshall gọi giữa Managed và Unmanaged heap?

EDIT

Cảm ơn trả lời của bạn nhưng những gì tôi đang hỏi là nói giả sử tôi làm một DllImport của user32.dll, đây rõ ràng là một dll không được quản lý và tôi gọi một số chức năng trong user32.dll bây giờ câu hỏi của tôi , CLR làm thế nào để kết nối cuộc gọi của tôi với dll chưa được sửa đổi này?

Trả lời

10

Bắt đầu thật dễ dàng. Pinvoke marshaller đầu tiên gọi LoadLibrary và chuyển tên DLL bạn đã chỉ định, thuộc tính DllImportAttribute.Value. Trong trường hợp của bạn, user32.dll đã được tải vì nó được nạp bởi .NET bootstrapper, số tham chiếu của nó chỉ được tăng lên. Nhưng thông thường bộ tải Windows được DLL ánh xạ vào không gian địa chỉ của quá trình để các chức năng xuất khẩu có thể được gọi.

Tiếp theo là GetProcAddress để lấy địa chỉ của hàm cần gọi, thuộc tính DllImportAttribute.EntryPoint. Marshaller thực hiện một vài lần thử trừ khi bạn sử dụng ExactSpelling. Một tên hàm như "foo" được kiểm tra một số cách có thể, foo và fooW hoặc fooA. Nasty chi tiết thực hiện của Win32 liên quan đến sự khác biệt giữa Unicode và Ansi ký tự. Các tài sản CharSet quan trọng ở đây.

Bây giờ tôi cần phải vẫy tay một chút vì nó trở nên phức tạp. Trình soạn thảo xây dựng một khung ngăn xếp, thiết lập các đối số cần được chuyển đến hàm được xuất. Điều này đòi hỏi mã cấp thấp, cẩn thận loại trừ khỏi con mắt tò mò. Mang nó theo mệnh giá mà nó thực hiện các loại bản dịch mà lớp Marshal hỗ trợ để chuyển đổi giữa các loại được quản lý và không được quản lý. Thuộc tính DllImportAttribute.CallingConvention quan trọng ở đây vì nó xác định giá trị đối số cần phải được đặt ở đâu để hàm được gọi có thể đọc nó đúng cách.

Tiếp theo, nó thiết lập trình xử lý ngoại lệ SEH để các ngoại lệ phần cứng được nêu ra bởi mã được gọi có thể bị phát hiện và dịch sang một ngoại lệ được quản lý. Một trong đó tạo ra một phổ biến hơn, AccessViolationException. Và những người khác.

Tiếp theo, nó sẽ đẩy một cookie đặc biệt lên ngăn xếp để cho biết mã không được quản lý sắp bắt đầu sử dụng ngăn xếp. Điều này ngăn cản bộ thu gom rác từ việc lấn át vào các khung ngăn xếp không được quản lý và giải thích các con trỏ mà nó tìm thấy ở đó dưới dạng các tham chiếu đối tượng được quản lý. Bạn có thể thấy cookie này trở lại trong ngăn xếp cuộc gọi của trình gỡ lỗi, [Được quản lý để chuyển tiếp bản địa].

Tiếp theo, chỉ cần gọi gián tiếp đến địa chỉ hàm như tìm thấy với GetProcAddress(). Điều đó khiến mã không được quản lý hoạt động.

Sau cuộc gọi, có thể cần phải dọn dẹp để giải phóng bộ nhớ được cấp phát để truyền các đối số không được quản lý. Giá trị trả lại có thể cần được dịch ngược trở lại giá trị được quản lý. Và đó là nó, giả sử không có gì khó chịu xảy ra, thực hiện tiếp tục trên báo cáo mã quản lý tiếp theo.

8

Phân bổ bộ nhớ không được quản lý đến từ vùng xử lý. Bạn chịu trách nhiệm phân bổ/deallocating bộ nhớ, vì nó sẽ không nhận được rác thu thập bởi vì GC không biết về các đối tượng này.

+0

Bạn có thể muốn tạo một wrapper xung quanh các thành phần không được quản lý và thực hiện các giao diện 'IDisposable', kiếm một cách sạch của deallocating nó. Bộ thu gom rác gọi hàm được định nghĩa trong giao diện này để ngăn không cho "quên" để dọn dẹp. –

+1

Bạn có thể bọc nó trong IDisposable, nhưng hãy chắc chắn rằng bạn gọi Dispose hoặc ghi đè lên finalizer. Chỉ cần thực hiện IDispose là không đủ, GC không gọi Dispose, nó gọi Object.Finalize (xem http://stackoverflow.com/questions/45036/will-the-gc-call-idisposable-dispose-for-me) – pstrjds

0

Một phần câu hỏi của bạn được trả lời bởi Michael. Tôi trả lời phần còn lại.

Nếu CLR được tải vào quy trình không được quản lý, nó được gọi là lưu trữ CLR. Điều này thường liên quan đến việc gọi một điểm vào trong mscoree DLL và sau đó AppDomain mặc định được nạp. Trong trường hợp này, CLR yêu cầu một khối bộ nhớ từ quá trình và khi được đưa ra, điều đó sẽ trở thành không gian bộ nhớ của nó và sẽ có một chồng và đống.

1

Cũng giống như một mảnh hàn lâm thông tin mở rộng về những gì đã được đăng ở đây:

Có khoảng 8 đống khác nhau mà CLR sử dụng:

  1. Loader Heap: chứa các cấu trúc CLR và loại hệ thống

  2. High Frequency Heap: tĩnh học, MethodTables, FieldDescs, bản đồ giao diện

  3. thấp frequ ency Heap: EEClass, ClassLoader và tra cứu bảng

  4. Stub Heap: khai cho CAS, giấy gói COM, P/Invoke

  5. Object lớn Heap: cấp phát bộ nhớ mà đòi hỏi nhiều hơn 85k byte

  6. GC heap: hướng dẫn phân bổ bộ nhớ heap riêng đến ứng dụng

  7. JIT mã heap: bộ nhớ được phân bổ bởi mscoreee (Thi Engine) và trình biên dịch JIT cho mã số quản lý

  8. Process/Cơ sở Heap: interop/phân bổ không được quản lý, bộ nhớ bản xứ, vv

HTH

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