Если я создам массив байт, например, и передам указатель на него в неуправляемый код, что с этим массивом будет делать Garbage Collector?
Ответ
В C# это зависит от того, как вы передаёте массив в неуправляемый код.
Обычно сборщик мусора имеет право в любой момент переместить любой управляемый объект в памяти. Чтобы этого не произошло, вы должны прикрепить объект, чтобы сборщик мусора не пытался его переместить. Для этого существует несколько методов, например, ключевое слово fixed
unsafe void F()
{
int[] data = { 1, 2, 3 };
fixed (int* p = &data[0])
{
// тут у вас есть указатель, можно передавать его в нативный код
}
}
Понятно, данные будут закреплены лишь в области действия fixed, поэтому если вы запомните указатель в переменной и воспользуетесь им по окончанию блока fixed, ваша память может быть перемещена или собрана сборщиком мусора, и вы на пути к undefined behaviour, как в старые недобрые времена. Ответственность за корректность поведения unsafe-кода лежит на вас и только на вас.
Для ручной работы с адресами вам могут понадобиться IntPtr (для представления указателя в безопасном коде), GCHandle (для низкоуровневого обращения с объектами с точки зрения сборщика мусора) и особенно Marshal для ручного преобразования между нативными и управляемыми объектами.
Другой метод передавать нативной функции массив — вызов через P/Invoke. В этом случае то же самое делает за вас маршаллер. Вам придётся выписать правильную сигнатуру P/Invoke, наподобие такой:
void F(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
long[] ar,
int size);
(сигнатуры можно составить самому, вдумчиво почитав документацию, или подсмотреть сигнатуры для популярных функций WinAPI на http://pinvoke.net). Маршаллинг не может проверить правильность сигнатуры, поэтому если вы ошибётесь, последствия, думаю, понятны.
Комментариев нет:
Отправить комментарий