Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Garbage Collector в неуправляемом коде

#java #c_sharp #net #сборщик_мусора


Если я создам массив байт, например, и передам указатель на него в неуправляемый
код, что с этим массивом будет делать Garbage Collector? 
    


Ответы

Ответ 1



В 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). Маршаллинг не может проверить правильность сигнатуры, поэтому если вы ошибётесь, последствия, думаю, понятны.

Ответ 2



В Java сборщик мусора не удалит массив, пока на него есть ссылка, но может его переместить. Поэтому, перед тем как работать с массивом, требуется в неуправляемом коде вызвать метод GetByteArrayElements или GetPrimitiveArrayCritical. Спецификация не накладывает жёстких требований к реализации этих методов и оставляет их на усмотрение реализации виртуальной машины. Скорее всего, GetByteArrayElements создаст копию в direct memory, а GetPrimitiveArrayCritical закрепит массив в куче. Во втором случае лучше не удерживать ссылку долго и не делать вызовов к виртуальной машине до освобождения ссылки. Естественно, в обоих случаях массив надо освободить до выхода из нативного метода.

Комментариев нет:

Отправить комментарий