GC có thể di chuyển các tham chiếu xung quanh; sử dụng không an toàn sẽ giữ một đối tượng nằm ngoài tầm kiểm soát của GC và tránh điều này. "Cố định" ghim một đối tượng, nhưng cho phép GC quản lý bộ nhớ.
Theo định nghĩa, nếu bạn có một con trỏ đến địa chỉ của một đối tượng và GC di chuyển nó, con trỏ của bạn không còn hợp lệ.
Về lý do tại sao bạn cần con trỏ: Lý do chính là làm việc với các tệp DLL không được quản lý, ví dụ như những tệp được viết bằng C ++
Cũng lưu ý, khi bạn ghim các biến và sử dụng con trỏ, bạn dễ bị phân mảnh đống.
Biên tập
Bạn đã đề cập đến vấn đề cốt lõi của mã được quản lý và không được quản lý ... làm thế nào để bộ nhớ được giải phóng?
Bạn có thể trộn mã cho hiệu suất như bạn mô tả, bạn chỉ không thể vượt qua ranh giới được quản lý / không được quản lý với con trỏ (tức là bạn không thể sử dụng con trỏ bên ngoài ngữ cảnh 'không an toàn').
Về cách chúng được làm sạch ... Bạn phải quản lý bộ nhớ của chính mình; các đối tượng mà con trỏ của bạn trỏ đến đã được tạo / cấp phát (thường trong C ++ DLL) bằng cách sử dụng (hy vọng) CoTaskMemAlloc()
và bạn phải giải phóng bộ nhớ đó theo cách tương tự, gọi CoTaskMemFree()
, nếu không bạn sẽ bị rò rỉ bộ nhớ. Lưu ý rằng chỉ có bộ nhớ được cấp phát với CoTaskMemAlloc()
có thể được giải phóng với CoTaskMemFree()
.
Giải pháp thay thế khác là hiển thị một phương thức từ dll C ++ gốc của bạn lấy một con trỏ và giải phóng nó ... điều này cho phép DLL quyết định cách giải phóng bộ nhớ, hoạt động tốt nhất nếu nó sử dụng một số phương pháp khác để cấp phát bộ nhớ. Hầu hết các hình nền gốc mà bạn làm việc đều là các hình nền của bên thứ ba mà bạn không thể sửa đổi và chúng thường không có (mà tôi đã thấy) các chức năng như vậy để gọi.
Một ví dụ về giải phóng bộ nhớ, được lấy từ đây :
string[] array = new string[2];
array[0] = "hello";
array[1] = "world";
IntPtr ptr = test(array);
string result = Marshal.PtrToStringAuto(ptr);
Marshal.FreeCoTaskMem(ptr);
System.Console.WriteLine(result);
Một số tài liệu đọc thêm:
Bộ nhớ deallocate C # được tham chiếu bởi IntPtr
Câu trả lời thứ hai giải thích các phương pháp phân bổ / deallocation khác nhau
Làm thế nào để giải phóng IntPtr trong C #?
Củng cố nhu cầu phân bổ theo cùng một cách bộ nhớ đã được cấp phát
http://msdn.microsoft.com/en-us/library/aa366533%28VS.85%29.aspx
Tài liệu MSDN chính thức về các cách khác nhau để cấp phát và phân bổ bộ nhớ.
Tóm lại ... bạn cần biết bộ nhớ được cấp phát như thế nào để giải phóng nó.
Chỉnh sửa
Nếu tôi hiểu chính xác câu hỏi của bạn, câu trả lời ngắn gọn là có, bạn có thể chuyển dữ liệu cho các con trỏ không được quản lý, làm việc với nó trong bối cảnh không an toàn và có sẵn dữ liệu khi bạn thoát khỏi ngữ cảnh không an toàn.
Điều quan trọng là bạn phải ghim đối tượng được quản lý mà bạn đang tham chiếu với một fixed
khối. Điều này ngăn không cho bộ nhớ bạn đang tham chiếu bị GC di chuyển khi ở trong unsafe
khối. Có một số vấn đề phức tạp ở đây, chẳng hạn như bạn không thể gán lại con trỏ được khởi tạo trong một khối cố định ... bạn nên đọc các câu lệnh không an toàn và cố định nếu bạn thực sự muốn quản lý mã của riêng mình.
Tất cả những gì đã nói, lợi ích của việc quản lý các đối tượng của riêng bạn và sử dụng con trỏ theo cách bạn mô tả có thể không giúp bạn tăng hiệu suất nhiều như bạn nghĩ. Lý do tại sao không:
- C # rất tối ưu hóa và rất nhanh
- Mã con trỏ của bạn vẫn được tạo dưới dạng IL, mã này phải được ghép nối (tại thời điểm này, các tính năng tối ưu hóa tiếp theo sẽ hoạt động)
- Bạn không tắt Trình thu gom rác ... bạn chỉ giữ các đối tượng bạn đang làm việc ngoài tầm nhìn của GC. Vì vậy, cứ sau 100 mili giây, GC vẫn ngắt mã của bạn và thực thi các chức năng của nó cho tất cả các biến khác trong mã được quản lý của bạn.
HTH,
James