C# fixed详解

相信不少人在这样或那样的项目中,或者无心间看到了fixed语句块,看到以后你确定会疑问:数组

  一、这个fixed关键字是作什么用的?安全

  二、什么状况下须要该关键字?性能

  三、这个关键字该怎么用?指针

  我相信解决了上面四个问题以后,你对这个fixed语句就理解和掌握到位了,我也在网上大体浏览了下,网上关于该关键字的详细说明太少太少了,基本都是摘抄MSDN官方文档,毫无自身理解与发散出来的东西,固然彻底依据MSDN的只言片文也能理解不过至关费劲,在这里我结合本身的理解给你们说明下该关键字的用法,但愿各位看过以后能给出本身的想法。对象

 

在MSDN以下介绍:索引

一、fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出如今不安全的上下文中。Fixed 还可用于建立固定大小的缓冲区。
二、fixed 语句设置指向托管变量的指针并在 statement 执行期间“钉住”该变量。若是没有 fixed 语句,则指向可移动托管变量的指针的做用很小,由于垃圾回收可能不可预知地重定位变量。C# 编译器只容许在 fixed 语句中分配指向托管变量的指针。
三、执行完语句中的代码后,任何固定变量都被解除固定并受垃圾回收的制约。所以,不要指向 fixed 语句以外的那些变量。
进程

 

看到这几乎话你可能云里雾里,雾里云里,内存

第一句:fixed禁止垃圾回收器定位可移动变量这究竟是怎么一回事?文档

  若是你不理解这句话说明你得须要去了解下GC,咱们知道GC是CLR管理下的垃圾回收器。当进程初始化时,CLR保留一块连续的地址空间,这个地址空间最初并无对应的物理存储空间,这个地址空间就是托管堆。在托管堆中,连续分配的对象能够确保他们在内存中时连续的。托管堆维护着一个叫作NextObjPtr的指针,它指向下一个对象在堆中的分配位置。调用new操做符建立对象时,若是没有足够的地址空间来分配对象,也即对象的字节数+NextObjPtr指针的地址超过了地址空间末尾则须要进行一次垃圾回收。编译器

  回收机制是采用根标记堆上的对象,当根不可达时则回收堆所占的内存(这里不去扩展,只给个大概的脉络,其实还涉及GC的代Generation),当回收完毕时的下一阶段就是压缩内存,这个阶段垃圾回收器线性的便利堆,以寻找未标记(垃圾)对象的连续内存块,若是发现的内存块比较小,垃圾回收期会忽略它们,可是,若是发现大的,可用的连续内存块,垃圾回收器会把非垃圾的对象移动到这里以压缩堆。

  很天然地,移动内存中的对象以后,包含“指向这些对象的指针”的变量和CPU寄存器如今都会变得无效。因此垃圾回收器必须从新访问应用程序的全部根,并修改它们来指向对象的新内存位置。另外,若是对象中的字段指向的是另外一个已移动了位置的对象,垃圾回收器要负责更正这些字段。堆内存压缩以后,托管堆的NextObjPtr指针指向紧接在最后一个非垃圾对象以后的对象以后的位置。

  到这里......哇 看了这么久你确定累了,能够休息下哈.................................................................................................

  上面所说的都是在托管环境的CLR指导下完成的,那若是是非安全代码若是是指针呢?指针指向了一个托管对象,而GC时内存会压缩,谁还管你的非安全指针,咱们CLR只负责托管代码啊!因此微软给出的解决办法是采用fixed关键字。

  因此当你看完到这里并且明白的话第1,2个问题都解决啦!!

  对于第三个问题,我采用一个实例结合MSDN说明:

C fixed语句固定变量详解 - 旭日 - 自由鸟

 

C fixed语句固定变量详解 - 旭日 - 自由鸟

  结合上面的理论,若是还能输出结果说明指针操做成功,没有由于GC的回收形成指针操纵了不正确的地址,由于fixed语句块钉住了ints变量,禁止垃圾回收器操做内存地址,重定位可移动变量。为何要这样作呢?咱们不是能够用托管代码直接操做数组吗?

  没错,但你别忘了指针操做数组是很快的,由于它会关闭数组索引的检查即关闭索引的上下限检查,这样的好处是:你的程序是性能优先,以性能为核心的时候这反而是最佳的解决方案!

相关文章
相关标签/搜索