Создание указателей в C#

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Привет всем, в данной статье я приведу несколько способов создания указателей в C#.

Указатели необходимы к примеру ,для взаимодействия с библиотеками, использующими ручное выделение/удаление блоков памяти.


Способы создания указателей

stackalloc

fixed

Marshal

Первым из них является stackalloc.

Выражение stackalloc выделяет блок памяти в стеке. Выделенный в стеке блок памяти, который создает этот метод, автоматически удаляется по завершении выполнения метода. Вы не можете явным образом освободить память, выделенную stackalloc. Выделенный в стеке блок памяти не подвергается сборке мусора

Ниже приведу фрагмент кода, создающего указатель с помощью stackalloc.

private static void Malloc(int Length)
        {
            unsafe
            {
                bool* n = stackalloc bool[Length];
            }
        }

Однако, стоит отметить, что выделение памяти имеет ограничение.

Так, попытка выделения в 64битном приложение , массива bool длиной 5 мегабайт (5 242 880 байт), создала StackOverflowExection .

В специфекации stackalloc ,отсутствует максимальный объем выделяемой памяти, но говорится следующее :

Объем доступной памяти в стеке ограничен. При выделении слишком большого объема памяти в стеке возникает исключение StackOverflowException.

Поскольку объем доступной памяти на стеке зависит от среды, в которой выполняется код, при определении фактического предельного значения следует использовать консервативное значение. Старайтесь не использовать stackalloc в циклах. Выделяйте блок памяти за пределами цикла и используйте его повторно внутри цикла.

В целом, stackalloc , полезен для ситуаций , когда не требуется выделять большой блок памяти .


Следующим способом создания указателя , является fixed .

Оператор fixed задает указатель на управляемую переменную и "закрепляет" эту переменную во время выполнения оператора. Указатели на перемещаемые управляемые переменные полезны только в контексте fixed. Без контекста fixed при сборке мусора эти переменные могут переноситься непредсказуемым образом. Компилятор C# позволяет присвоить указатель только управляемой переменной в операторе fixed.

Оператор fixed не позволяет сборщику мусора переносить перемещаемую переменную. Оператор fixed допускается только в небезопасном контексте. Можно также использовать ключевое слово fixed для создания буферов фиксированного размера.

Ниже приведу фрагмент кода , использующего оператор fixed для создания указателя :

static void Copy(int[]m,out int[]n,int offset,int Length)
        {
            n = new int[Math.Min(m.Length - offset, Length)];
            unsafe
            {
                fixed(int* _m = m, _n = n)
                {

                   
                    Copy(_m, _n, offset, n.Length);
                }
            }
        }
        static unsafe void Copy(int *_inp,int *_out,int offset,int Length)
        {
            Parallel.For(0, Length, r => {
                _out[r] = _inp[r + offset];
            });
        }

Сразу отмечу, что к указателю , созданному в блоке fixed , нельзя получить доступ из Parallel.For . Также , указатель созданный в блоке fixed , нельзя приравнивать к другому указателю. Если указатели относятся к 1 типу данных, их можно поместить в 1 оператор fixed .


Ещё одним способом создания указателя является библиотечный класс Marshal . Данный класс находится в пространстве имен System.Runtime.InteropServices .

Предоставляет коллекцию методов для выделения неуправляемой памяти, копирования блоков неуправляемой памяти и преобразования управляемых типов в неуправляемые, а также прочих разнообразных методов, используемых при взаимодействии с неуправляемым кодом.

В данном классе присутствуют 2 метода , позволяющих выделять память под указатели .

FreeHGlobal(IntPtr)

Освобождает память, выделенную ранее из неуправляемой памяти процесса.

AllocHGlobal(Int32)

Выделяет память из неуправляемой памяти процесса, используя заданное количество байтов.

FreeCoTaskMem(IntPtr)

Освобождает блок памяти, выделенный неуправляемым механизмом распределения памяти для задач COM.

AllocCoTaskMem(Int32)

Выделяет блок памяти указанного размера из механизма распределения памяти для задач COM.

В случае использования AllocHGlobal и AllcCoTaskMem выделенную память необходимо очистить с помощью методов FreeHGlobal и FreeCoTaskMem соответственно . AllocHGlobal способен выделить до 2 гигабайт памяти , AllcCoTaskMem в отличии от него , способен работать и с большим объемом .

Всем спасибо за внимание .

Источник: https://habr.com/ru/post/573054/


Интересные статьи

Интересные статьи

Всем привет. Если вы когда-либо работали с универсальными списками в Битрикс24, то, наверное, в курсе, что страница детального просмотра элемента полностью идентична странице редак...
Данное руководство, является "форком" одноименной статьи про CentOS 5.9, и учитывает особенности новой OS. На данный момент в AWS Marketplace нет официального образа Centos8 от centos....
Устраивать конкурсы в инстаграме сейчас модно. И удобно. Инстаграм предоставляет достаточно обширный API, который позволяет делать практически всё, что может сделать обычный пользователь ручками.
Принято считать, что персонализация в интернете это магия, которая создается сотнями серверов на основе БигДата и сложного семантического анализа контента.
В предыдущей статье на тему дизайна таблиц в Фигме мы выяснили, что базовый элемент создания любого data grid — это компонент ячейки, внутри которого спрятано все необходимое для того, чтобы ...