C#内存管理:不安全的关键字和指针

Ale*_*rty 33 c# pointers memory-management unsafe keyword

C#中使用unsafe关键字使用指针会产生什么后果(正面/负面)?例如,什么是垃圾收集,性能增益/损失是什么,与其他语言手动内存管理相比,性能增益/损失是什么,危险是什么,在哪种情况下使用这种语言是合理的功能,编译时间更长......?

Tom*_*cek 27

正如Conrad已经提到的,在某些情况下,C#中对内存的不安全访问很有用.没有那么多,但有一些:

  • 操作Bitmap几乎是一个典型的例子,您需要通过使用获得一些额外的性能unsafe.

  • 与旧API(如WinAPI或本机C/C++ DLL)的互操作性是另一个unsafe非常有用的领域 - 例如,您可能希望调用一个接受/返回非托管指针的函数.

另一方面,您可以使用Marshall编写大部分内容,这会隐藏方法调用中的许多不安全操作.这会慢一点,但是如果你想避免使用它unsafe(或者如果你使用的是没有的VB.NET unsafe)它是一个选项

积极的结果:所以,存在的主要积极后果unsafe在C#中,你可以更容易地(互操作性)编写一些代码,你可以更有效地编写一些代码(位图操纵或可能使用数组一些沉重的数值计算-虽然,我不太确定第二个).

负面后果:当然,您需要为使用付出一些代价unsafe:

  • 不可验证的代码:使用这些unsafe功能编写的C#代码变得不可验证,这意味着您的代码可能以任何方式危及运行时.在完全信任的情况下(例如,不受限制的桌面应用程序),这不是一个大问题- 您只是没有所有漂亮的.NET CLR保证.但是,您无法在受限制的环境中运行应用程序,例如公共Web托管,Silverlight或部分信任(例如,从网络运行的应用程序).

  • 垃圾收集器在使用时也需要小心unsafe.通常允许GC重新定位托管堆上的对象(以保持内存碎片整理).当您获取指向某个对象的指针时,您需要使用该fixed关键字告诉GC它在完成之前无法移动对象(这可能会影响垃圾收集的性能 - 但当然,具体取决于具体情况).

我的猜测是,如果C#没有与旧代码进行互操作,它可能不会支持unsafe(和研究项目,如奇异试图创建基于托管语言绝对不允许usnsafe代码更可验证的操作系统).然而,在现实世界中,unsafe在一些(罕见)情况下是有用的.


Con*_*cht 9

我可以告诉你一个值得使用的情况:

我必须逐个像素地生成位图.Drawing.Bitmap.SetPixel()太慢了.所以我构建了自己的托管Array位图数据,并用于unsafe获取IntPtrfor Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr).


Osk*_*lin 5

引用Professional C#2008:

“使用指针的两个主要原因是:

  1. 向后兼容性 -尽管.NET运行时提供了所有功能,但仍然可以调用本机Windows API函数,对于某些操作,这可能是完成任务的唯一方法。这些API函数通常用C编写,并且经常需要使用指针作为参数。但是,在许多情况下,可以以避免使用指针的方式编写DllImport声明。例如,通过使用System.IntPtr类。
  2. 性能 -在那些速度至关重要的场合,指针可以为优化性能提供一条途径。如果您知道自己在做什么,则可以确保以最有效的方式访问或操作数据。但是,请注意,代码的其他部分通常可以在不影响指针的情况下进行必要的性能改进。尝试使用代码分析器在代码中查找瓶颈-Visual Studio 2008附带了一个瓶颈。”

而且,如果使用指针,则代码将需要更高的信任度才能执行,并且如果用户未授予许可,则代码将不会运行。

并用最后一个引号括起来:

“我们强烈建议不要使用不必要的指针,因为这样不仅会更难编写和调试,而且还会使CLR进行的内存类型安全检查失败。”