Ответ 1
Ну, конечно, есть разница, вы это видели. CLR поддерживает несколько способов привязки объекта. Только метод GCHandleType.Pinned напрямую подвергается действию кода пользователя. Но есть и другие, такие как "async pinned handleles" , функция, которая поддерживает буферизацию ввода-вывода, когда драйвер выполняет операцию перекрытия ввода-вывода. И тот, который использует фиксированное ключевое слово, он вообще не использует явный вызов дескриптора или метода. Эти дополнительные способы были добавлены, чтобы сделать повторное удаление объектов еще более быстрым и надежным, что очень важно для здоровья GC.
Фиксированные булавки буферов реализуются дрожанием. Который выполняет два важных задания, когда он переводит MSIL на машинный код, очень заметным является сам машинный код, вы можете легко увидеть его с помощью отладчика. Но он также генерирует структуру данных, используемую сборщиком мусора, полностью невидимую в отладчике. Требуется GC для надежного поиска обратных ссылок на объекты, которые хранятся в фрейме стека или в регистре CPU. Подробнее об этой структуре данных в этом ответе.
Джиттер использует атрибут [закрепленный] в объявлении переменной в метаданных, чтобы установить бит в этой структуре данных, указывая, что объект, на который ссылается переменная, временно привязан. GC видит это и знает, чтобы не перемещать объект. Очень эффективен, потому что он не требует явного вызова метода для выделения дескриптора и не требует хранения.
Но нет, эти трюки не доступны в противном случае для кода С#, вам действительно нужно использовать фиксированное ключевое слово в вашем коде. Или GCHandle.Alloc(). Если вы обнаруживаете, что теряетесь в булавках, то высокие шансы, что вы должны рассматривать pinvoke или С++/CLI, чтобы вы могли легко называть собственный код. Временные контакты, которые используется маркерщиком pinvoke для сохранения объектов в то время как собственный код работает, являются еще одним примером автоматического пиннинга, который не требует явного кода.