相信很多人在这样或那样的项目中,或者无意间看到了fixed语句块,看到之后你肯定会疑问:

1,这个fixed关键字是做什么用的?

2,什么情况下需要该关键字?

3,这个关键字该怎么用?

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

本文地址:http://hi.baidu.com/jiang_yy_jiang/blog/item/de22fcd15d017f269a502770.html

在MSDN如下介绍:

1、fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出现在不安全的上下文中。Fixed 还可用于创建固定大小的缓冲区。
2、fixed 语句设置指向托管变量的指针并在 statement 执行期间“钉住”该变量。如果没有 fixed 语句,则指向可移动托管变量的指针的作用很小,因为垃圾回收可能不可预知地重定位变量。C# 编译器只允许在 fixed 语句中分配指向托管变量的指针。
3、执行完语句中的代码后,任何固定变量都被解除固定并受垃圾回收的制约。因此,不要指向 fixed 语句之外的那些变量。

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

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

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

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

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

   到这里......哇 看了这么久你肯定累了,可以休息下哈.................................................................................................

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

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

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

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

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

C# fixed语句固定变量详解的更多相关文章

  1. [转]mysqldump备份还原和mysqldump导入导出语句大全详解

    FROM : http://www.cnblogs.com/zeroone/archive/2010/05/11/1732834.html mysqldump备份还原和mysqldump导入导出语句大 ...

  2. shell 脚本之判断语句 if 详解

    使用 Linux 系统这么长时间,对 shell 脚本也算是比较熟悉.其实不管是搞开发,还是搞运维,shell 脚本都是必备的基本技能.这次抽时间好好总结一下 shell 方面的知识,综合的再学习一下 ...

  3. MySQL查询语句(select)详解(2)

    7.子查询 当进行查询的时候,需要的条件是另外一个select语句的结果,这时候就要用到子查询 用于子查询的主要关键字有:in,not in,=,!=,exists,not exists等. 以下两张 ...

  4. static{ }语句块详解

    static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法.举ge例子: public class Test { public static i ...

  5. 转 java中static{}语句块详解

    原文地址:http://blog.csdn.net/lubiaopan/article/details/4802430     感谢原作者! static{}(即static块),会在类被加载的时候执 ...

  6. java中static{}语句块详解

    static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法,下面我们详细的讨论一下该语句块的特性及应用. 一.在程序的一次执行过程中,stati ...

  7. hive操作语句使用详解

    #创建表人信息表  person(String name,int age) hive> create table person(name STRING,age INT)ROW FORMAT DE ...

  8. SQL语句函数详解__sql聚合函数

    函数是一种有零个或多个参数并且有一个返回值的程序.在SQL中Oracle内建了一系列函数,这些函数都可被称为SQL或PL/SQL语句,函数主要分为两大类:单行函数.组函数 本文将讨论如何使用单行函数及 ...

  9. JavaScript 循环语句入门详解

    JavaScript Switch 语句 语法 switch(n) { case 1: 执行代码块 1 break; case 2: 执行代码块 2 break; default: n 与 case ...

随机推荐

  1. 深刻理解Docker镜像大小

    都说容器大法好,可是假设没有Docker镜像,Docker该是多无趣啊. 是否还记得第一个接触Docker的时候,你从Docker Hub下拉的那个镜像呢?在那个处女镜像的基础上.你执行了容器生涯的处 ...

  2. BZOJ 1007: [HNOI2008]水平可见直线 平面直线

    1007: [HNOI2008]水平可见直线 Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则 ...

  3. HDU 4609 FFT+各种分类讨论

    思路: http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html 其实我是懒得写了.... 一定要define int long ...

  4. Gradle学习总结

    Gradle学习系列 (1). Gradle快速入门 (2). 创建Task的多种方法 (3). 读懂Gradle语法 (4). 增量式构建 (5). 自定义Property (6). 使用java ...

  5. Codeforces 959E. Mahmoud and Ehab and the xor-MST 思路:找规律题,时间复杂度O(log(n))

    题目: 解题思路 这题就是0,1,2...n-1总共n个数字形成的最小生成树. 我们可以发现,一个数字k与比它小的数字形成的异或值,一定可以取到k与所有正整数形成的异或值的最小值. 要计算n个数字的情 ...

  6. Pyinstaller 0

    Pyinstaller 是一个小的可以打包我们所写的Python脚本,来生成相应的可执行文件. 它是怎么工作的? PyInstaller读取您编写的Python脚本.它会分析您的代码,以发现您的脚本执 ...

  7. 【原创】关于not in的一些事情

    早上到公司,收到一条cocall消息,是某哥们遇到的疑惑,可能很多新手并不知情: 请教个问题 我执行 . select * from t_htgl_htpswj t where t.c_wjmc = ...

  8. JavaScript 中表达式和语句的区别

    1.语句和表达式 JavaScript中的表达式和语句是有区别的.一个表达式会产生一个值,它可以放在任何需要一个值的地方,比如,作为一个函数调用的参数.下面的每行代码都是一个表达式: myvar3 + ...

  9. Nginx域名配置文件bak

    server { listen 80; server_name m.abd.com; rewrite ^(.*)$ https://$host$1 permanent; } server { list ...

  10. Ibatis使用技巧

    一.在ibatis中以Map形式返回查询结果 1.在ibatis的配置文件中配置以HashMap返回的resultMap <resultMap id="MAX_MIN_ID_RESUL ...