Когда использовать указатели в C# / .NET?



Я знаю, что C# дает программисту возможность доступа, использовать указатели в небезопасном контексте. Но когда это нужно?



при каких обстоятельствах использование указателей становится неизбежным?



Это только из соображений производительности?



также почему C# предоставляет эту функциональность через небезопасный контекст и удаляет из нее все управляемые преимущества? Можно ли использовать указатели без потери каких-либо преимуществ управляемой среде, теоретически?

599   5  

5 ответов:

когда это необходимо? При каких обстоятельствах использование указателей становится неизбежным?

когда чистая стоимость управляемого, безопасного решения неприемлема, но чистая стоимость небезопасного решения приемлема. Вы можете определить чистую стоимость или чистую выгоду, вычитая общую выгоду из общей стоимости. Преимущества небезопасного решения-это такие вещи, как" нет времени, потраченного на ненужные проверки времени выполнения для обеспечения правильности"; затраты (1) имеют писать код, который безопасен даже при отключенной управляемой системе безопасности, и (2) иметь дело с потенциальным снижением эффективности сборщика мусора, поскольку он не может перемещаться по памяти, в которой есть неуправляемый указатель.

или, если вы человек, пишущий слой сортировки.

Это только из соображений производительности?

Кажется извращенным использовать указатели на управляемом языке по причинам, отличным от производительности.

вы можете использовать методы класса Marshal для взаимодействия с неуправляемым кодом в подавляющем большинстве случаев. (Может быть, есть несколько случаев, в которых трудно или невозможно использовать Сортировочное устройство для решения проблемы взаимодействия, но я не знаю ни одного.)

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

почему C# предоставляет эту функциональность через небезопасный контекст и удаляет из нее все управляемые преимущества?

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

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

можно ли использовать указатели без потери каких-либо преимуществ управляемой среде, теоретически?

под "преимуществами" я предполагаю, что вы имеете в виду преимущества, такие как мусор сбор, безопасность типов и ссылочная целостность. Таким образом, ваш вопрос по существу: "теоретически можно отключить систему безопасности, но все же получить преимущества включения системы безопасности?- Нет, это явно не так. Если вы отключите эту систему безопасности, потому что вам не нравится, насколько она дорогая, тогда вы не получите преимуществ от ее включения!

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

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

все это будет решаться с помощью GC-отслеживаемых указателей; вот что ссылки являются.

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

GC может перемещать ссылки; использование unsafe сохраняет объект вне контроля GC и избегает этого. "Исправлено" закрепляет объект, но позволяет GC управлять памятью.

по определению, если у вас есть указатель на адрес объекта и сборщик мусора перемещает его, указатель больше не действителен.

Что касается того, зачем вам нужны указатели: основная причина заключается в работе с неуправляемыми DLL, например, написанными на C++

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


Edit

Вы затронули основную проблему управляемого и неуправляемого кода... как освобождается память?

вы можете смешивать код для производительности, как вы описываете, вы просто не можете пересекать управляемые/неуправляемые границы с указателями (т. е. вы не можете использовать указатели вне "небезопасного" контекста).

Что касается того, как они очищаются... Вы должны управлять своими собственными память; объекты, на которые указывают ваши указатели, были созданы / выделены (обычно в библиотеке DLL C++) с помощью (надеюсь) CoTaskMemAlloc(), и вы должны освободить эту память таким же образом, вызывая CoTaskMemFree(), или у вас будет утечка памяти. Обратите внимание, что только память, выделенная с CoTaskMemAlloc() можно освободить с помощью CoTaskMemFree().

другой альтернативой является предоставление метода из вашей собственной библиотеки dll C++, который берет указатель и освобождает его... это позволяет DLL решить, как освободить память, которая лучше всего работает, если она используется какой-то другой метод выделения памяти. Большинство собственных библиотек DLL, с которыми вы работаете, являются сторонними библиотеками DLL, которые вы не можете изменить, и у них обычно нет (что я видел) таких функций для вызова.

пример освобождения памяти, взятый из здесь:

string[] array = new string[2];
array[0] = "hello";
array[1] = "world";
IntPtr ptr = test(array);
string result = Marshal.PtrToStringAuto(ptr);
Marshal.FreeCoTaskMem(ptr);
System.Console.WriteLine(result);


Еще несколько материалов для чтения:

C# освободить память, на которую ссылается IntPtr Второй ответ вниз объясняет различное распределение / освобождение методы

как освободить IntPtr в C#? Усиливает необходимость освобождения таким же образом, как была выделена память

http://msdn.microsoft.com/en-us/library/aa366533%28VS.85%29.aspx Официальная документация MSDN о различных способах выделения и освобождения памяти.

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


Edit Если я понимаю ваш вопрос правильно, короткий ответ-да, вы можете передать данные неуправляемым указателям, работать с ними в небезопасном контексте и иметь данные, доступные после выхода из небезопасного контекста.

ключ заключается в том, что вы должны закрепить управляемый объект, на который вы ссылаетесь, с помощью fixed блок. Это предотвращает перемещение памяти, на которую вы ссылаетесь, GC, находясь в unsafe блок. Здесь есть несколько тонкостей, например, вы не можете переназначить инициализированный указатель в фиксированном блоке... вы должны прочитать о небезопасных и фиксированных операторах, если вы действительно настроены на управление своим собственным кодом.

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

  1. C# очень оптимизирован и очень быстрый
  2. ваш код указателя по-прежнему генерируется как IL, который должен быть jitted (при котором точка дальнейшей оптимизации вступают в игру)
  3. вы не выключаете сборщик мусора... вы просто держите объекты, с которыми вы работаете, вне компетенции GC. Так что каждые 100 мс или около того, GC еще прерывает код и выполняет его функции для всех других переменных в управляемом коде.

HTH,
Джеймс

наиболее распространенные причины использования указателей явно в C#:

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

причина, по которой синтаксис, связанный с указателями, был удален из C# (согласно моим знаниям и точке зрения - Джон Скит ответил бы лучше B -)), оказалась лишней в большинстве ситуаций.

из языкового дизайна перспектива, как только вы управляете памятью сборщиком мусора, вы должны ввести серьезные ограничения на то, что есть и что невозможно сделать с указателями. Например, использование указателя для указания на середину объекта может вызвать серьезные проблемы с GC. Следовательно, как только ограничения будут установлены, Вы можете просто опустить дополнительный синтаксис и получить "автоматические" ссылки.

кроме того, ультра-доброжелательный подход, найденный в C/C++, является распространенным источником ошибок. Для большинства ситуаций, там, где микро-производительность не имеет никакого значения, лучше предложить более жесткие правила и ограничить разработчика в пользу меньшего количества ошибок, которые было бы очень трудно обнаружить. Таким образом, для обычных бизнес-приложений так называемые "управляемые" среды, такие как .NET и Java, лучше подходят, чем языки, которые предполагают работать с голой металлической машиной.

скажем, вы хотите общаться между 2 приложения с помощью IPC (общая память), то вы можете маршалировать данные в память и передать этот указатель данных в другое приложение с помощью обмена сообщениями windows или что-то. При получении приложения вы можете получить данные обратно.

полезно также в случае передачи данных из .NET в устаревшие приложения VB6, где вы будете маршалировать данные в память, передавать указатель на приложение VB6 с помощью win msging, использовать VB6 copymemory() для извлечения данных из управляемой памяти пространство для приложений VB6 неуправляемое пространство памяти..

Comments

    Ничего не найдено.