В небезопасном контексте может возникнуть необходимость в объявлении локальной переменной, для которой память выделяется непосредственно в стеке вызовов (и потому она не обрабатывается сборщиком мусора .NET Core). Для этого в языке C# предусмотрено ключевое слово stackalloc
_аllоса библиотеки времени выполнения С. Вот простой пример:static unsafe string UnsafeStackAlloc
{
char* p = stackalloc char[52];
for (int k = 0; k < 52; k++)
{
p[k] = (char)(k + 65)k;
}
return new string(p);
}
Закрепление типа посредством ключевого слова fixed
В предыдущем примере вы видели, что выделение фрагмента памяти внутри небезопасного контекста может делаться с помощью ключевого слова stackalloc
stackalloc выделенная память очищается, как только выделяющий ее метод возвращает управление (т.к. память распределена в стеке). Однако рассмотрим более сложный пример. Во время исследования операции -> создавался тип значения по имени Point. Как и все типы значений, выделяемая его экземплярам память исчезает из стека по окончании выполнения. Предположим, что тип Point взамен определен как class PointRef // <= Renamed and retyped.
{
public int x;
public int y;
public override string ToString => $"({x}, {y})";
}
Как вам известно, если в вызывающем коде объявляется переменная типа Point
Point именно в тот момент, когда происходит реорганизация кучи! Теоретически может случиться так, что небезопасный контекст попытается взаимодействовать с членом, который больше не доступен или был перемещен в другое место кучи после ее очистки с учетом поколений (что является очевидной проблемой).Для фиксации переменной ссылочного типа в памяти из небезопасного контекста язык C# предлагает ключевое слово fixed
fixed устанавливает указатель на управляемый тип и "закрепляет" такую переменную на время выполнения кода. Без fixed от указателей на управляемые переменные было бы мало толку, поскольку сборщик мусора может перемещать переменные в памяти непредсказуемым образом. (На самом деле компилятор C# даже не позволит установить указатель на управляемую переменную, если оператор fixed отсутствует.)Таким образом, если вы создали объект Point
unsafe static void UseAndPinPoint
{
PointRef pt = new PointRef
{
x = 5,
y = 6
};
// Закрепить указатель pt на месте, чтобы он не мог
// быть перемещен или уничтожен сборщиком мусора.
fixed (int* p = &pt.x)
{
// Использовать здесь переменную int*!
}
// Указатель pt теперь не закреплен и готов
// к сборке мусора после завершения метода.
Console.WriteLine ("Point is: {0}", pt);
}
Выражаясь кратко, ключевое слово fixed
Ключевое слово sizeof
Последнее ключевое слово С#, связанное с небезопасным кодом — sizeof
sizeof в C# используется для получения размера в байтах sizeof относятся к встроенным типам:static void UseSizeOfOperator
{
Console.WriteLine("The size of short is {0}.", sizeof(short));
Console.WriteLine("The size of int is {0}.", sizeof(int));
Console.WriteLine("The size of long is {0}.", sizeof(long));
}
Бьёрн Страуструп , Ирина Сергеевна Козлова , Бьерн Страуструп , Валерий Федорович Альмухаметов
Программирование, программы, базы данных / Базы данных / Программирование / Учебная и научная литература / Образование и наука / Книги по IT