Иллюстрированный самоучитель по Architecture .NET

Закрепление управляемых объектов

Ключевое слово _pin (закрепить) указывает на то, что указатель на управляемый объект будет оставаться корректным (т.е. общеязыковая среда выполнения CLR не переместит Объект в памяти) на протяжении существования закрепленного указателя. Закрепленный Объект остается на своем месте в памяти до тех пор, пока на него указывает закрепленный указатель. Если изменить указатель так, что он будет указывать на другой объект или присвоить ему нулевое значение, объект может быть перемещен сборщиком мусора. Когда при определении указателя не задано ключевое слово _pin (закрепить), общеязыковая среда выполнения CLR может в любой момент переместить объект, на который указывает этот указатель.

Перемещение объектов происходит вследствие сборки мусора и уплотнения динамически распределяемой области памяти, выполняемых общеязыковой средой выполнения CLR. Эти перемещения не сказываются на управляемом коде, так как общеязыковая среда выполнения CLR автоматически изменяет значения управляемых указателей при перемещении объектов, но могут повлиять на выполнение неуправляемого кода, в котором используются неуправляемые указатели на управляемые объекты.

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

Ниже приведен фрагмент, иллюстрирующий использование ключевого слова _pin (закрепить) в описанной ситуации. Обратите внимание, что объект pPinnedObject закреплен в памяти, так что передача указателя на него методам SetGlobalPointerValue и GetGlobalPointerValue в качестве аргумента является допустимой. Реализация этих методов основана на том, что глобальный указатель gх остается корректным, а это может быть верны только в случае, когда общеязыковая среда выполнения CLR не будет перемещать объект класса ManagedClass. Заметим, что компилятор способен предсказать возникновение такой ситуации и выдаст сообщение об ошибке, если из приведенного примера удалить ключевое слово _pin (закрепить).

//PinExample.срр
#using <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
_gc class ManagedClass
// класс сборщика мусора ManagedClass
{
public:
int x; };
ttpragma unmanaged // неуправляемый
int *gx; // глобальный указатель void SetGlobalPointer(int* pi)
{
// установить глобальный указатель,
// чтобы указать на управляемый объект
gx = pi;
}
void SetGlobalPointerValue(int i)
{
// установить управляемый объектный элемент данных
// через глобальный указатель
*gx = i;
}
int GetGlobalPointerValue()
{
// получить управляемый объектный элемент данных
// через глобальный указатель
return *gx;
}
Ipragma managed // управляемый
void main()
{
ManagedClass _pin * pPinnedObject = new ManagedClass;
// обратите внимание на ошибку, генерируемую компилятором
//в следующей инструкции…
// если ключевое слово _pin удалить из предыдущей инструкции
SetGlobalPointer(&pPinnedObject › x); // неуправляемый
SetGlobalPointerValue(1); // неуправляемый
int x = GetGlobalPointerValue();//неуправляемый
}
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.