необходимо ли gchandle.alloc () каждый обратный вызов в классе? - PullRequest
5 голосов
/ 04 ноября 2010

У меня есть класс .NT, который имеет несколько делегатов для обратных вызовов из собственного кода. Нужно ли выделять всех делегатов? Я имею в виду, защищает ли GCHandle.Alloc() только делегата или весь класс, которому принадлежит делегат, от сбора?

Ответы [ 3 ]

8 голосов
/ 04 ноября 2010

Делегат имеет два соответствующих свойства: Метод и Цель. Цель будет ненулевой, если делегат был создан для метода экземпляра. И это сохраняет объект живым, пока сборщик мусора может видеть экземпляр делегата.

Собственный код имеет отношение к проблемам с обратными вызовами. Когда вы передаете экземпляр делегата в встроенную функцию с привязкой, тогда маршаллер P / Invoke будет использовать Marshal.GetFunctionPointerForDelegate () для создания небольшой заглушки, которая создает требуемую ссылку Target, когда собственный код выполняет обратный вызов. Однако сборщик мусора не может видеть эту заглушку и поэтому не найдет ссылку на объект делегата. И собирает это. Следующий обратный вызов из нативного кода вызывает сбой.

Чтобы избежать этого, вы должны хранить объект делегата самостоятельно, чтобы на него ссылались до тех пор, пока нативный код может выполнить обратный вызов. Хранение его в статической переменной является очевидным решением.

2 голосов
/ 12 октября 2013

Я не прав.Вам не нужно закреплять делегата (с другой стороны, вы не можете закрепить делегата, будет сгенерировано исключение (System.ArgumentException: объект содержит не примитивные или неблизкие данные.)

ссылка: http://social.msdn.microsoft.com/Forums/vstudio/en-US/bd662199-d150-4fbf-a5ee-7a06af0493bb/interop-pinning-and-delegates?forum=

Подробности об этом в блоге Криса Брумма http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx

Крис Брумме писал: По тем же принципам управляемые делегаты могут быть преобразованы в неуправляемый код, гдеони представляются как указатели неуправляемых функций. Вызовы этих указателей будут выполнять неуправляемый переход к управляемому, изменение соглашения о вызовах, вход в правильный домен приложения и маршалинг любого необходимого аргумента. Очевидно, указатель неуправляемой функции должен ссылаться на фиксированный адрес.Это было бы катастрофой, если бы GC переместил это! Это приводит к тому, что многие приложения создают дескриптор закрепления для делегата. Это совершенно не нужно. Указатель неуправляемой функции фактически ссылается на заглушку собственного кода, которую мы динамически генерируем для выполнения перехода.и маршалинг.Эта заглушка существует в фиксированной памяти вне кучи GC.

Однако приложение отвечает за то, чтобы как-то продлить срок службы делегата до тех пор, пока из неуправляемого кода не будет больше вызовов.Время жизни нативной заглушки кода напрямую связано со временем жизни делегата.После того, как делегат собран, последующие вызовы через указатель неуправляемой функции могут вызвать сбой или иным образом повредить процесс.В нашем недавнем выпуске мы добавили Customer Debug Probe, который позволяет вам точно обнаружить эту - слишком распространенную - ошибку в вашем коде.Если вы еще не начали использовать Customer Debug Probes во время разработки, ознакомьтесь!

1 голос
/ 10 октября 2013

Я думаю, что произойдет что-то не так (но не всегда), когда вы просто сохраните объект делегата.Как мы все знаем, управляемая память будет организована сборщиком мусора.(Это означает, что адрес физической памяти управляемого объекта будет изменен.)

Представление о том, что существует долговременный делегат, который будет вызываться собственным кодом, мы устанавливаем делегат как статический член или член класса,Но иногда (мы не знаем, когда, мы просто знаем, что это произойдет), GC упорядочил память, и физическая память делегата может быть от 0x000000A до 0x0000010.Но нативный код ничего не знает об этом, а нативный код знает, что он всегда звонит по адресу 0x000000A.Таким образом, мы должны не только хранить объект делегата, но также использовать GCHandle.Alloc, чтобы сказать GC не перемещать физическую память объекта делегата.Тогда нативный код преуспеет во время обратного вызова.

Хорошо, поскольку GC не организует управляемую память часто, поэтому для делегата с коротким сроком службы даже вы не вызываете GCHandle.Alloc , yourкоды всегда "DO WELL" , но иногда это будет безумием.Теперь вы знаете причину.

ссылка: http://dotnet.dzone.com/news/net-memory-control-use-gchandl

...