C# fixed语句固定变量详解

相信很多人在这样或那样的项目中,或者无意间看到了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变量,禁止垃圾回收器操作内存地址,重定位可移动变量。为什么要这样做呢?我们不是可以用托管代码直接操作数组吗?

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

时间: 2024-10-15 03:16:58

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

MySQL语句explain详解

我们一般再检查一个SQL语句执行效率的时候,通常会首先用explain来看下该语句的相关情况.虽然经常使用,但时候你深刻的理解了其结果中每个字段的含义呢?其中type字段是我们关注的重中之重.type字段的归纳:     连接类型     system          表只有一行     const           表最多只有一行匹配,通用用于主键或者唯一索引比较时     eq_ref          每次与之前的表合并行都只在该表读取一行,这是除了system,const之外最好的一

hive操作语句使用详解

#创建表人信息表  person(String name,int age) hive> create table person(name STRING,age INT)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' ESCAPED BY '\\' STORED AS TEXTFILE; OK Time taken: 0.541 seconds#创建表票价信息表 ticket(int age,float price) hive> create tab

static{}语句块详解

static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法,下面我们详细的讨论一下该语句块的特性及应用. 一.在程序的一次执行过程中,static{}语句块中的内容只被执行一次,看下面的示例: 示例一 [java] view plain copy class Test{ public static int X=100; public final static int Y;=200 public Test(){ System.out.prin

Hibernate 的update语句性能详解

Hibernate 中如果直接使用 Session.update(Object o); 会把这个表中的所有字段更新一遍. 比如: view plaincopy to clipboardprint? public class TeacherTest { @Test public void update(){ Session session = HibernateUitl.getSessionFactory().getCurrentSession(); session.beginTransactio

java中static{}语句块详解

1.当一个类中有多个static{}的时候,按照static{}的定义顺序,从前往后执行: 2.先执行完static{}语句块的内容,才会执行调用语句: 示例二 public class TestStatic{    static{        System.out.println(1);    }    static {        System.out.println(2);    }    static {        System.out.println(3);    }    p

mysql数据库 详解 之 自学成才1

一.学习目录 1.认识数据库和mysql 2.mysql连接 3.入门语句 4.详解列类型 5.增删改查 INSERT INTO  表名(列1,--  列n)  VALUES(值 1,--  值 n); *(列1,--  列n)允许不写,如果不写,则默认插入所有列 INSERT INTO  表名  VALUES(值 1,--  值 n); *VALUES 对应的值的输入顺序与表中字段顺序一致 改: update 表名 set 列1 = 新值1, 列2 = 新值2, where expr *改哪张

mysqldump导入导出详解

mysqldump可以指定路径的,如果没指定路径,而只写了文件名的话,那么就在当前进入mysql命令行所在的目录,也就是mysql安装目录下 mysqldump  --default-character-set=utf8 -h127.0.0.1  -uroot -pabctrans -P33061 db table1 able2 |gzip > db`date +%Y%m%d`.tar.gz mysqldump  --default-character-set=utf8 -h127.0.0.1 

try-catch-finally详解

参考http://blog.sina.com.cn/s/blog_4f1c99de0100tyty.html try{//代码区}catch(Exception e){//异常处理}代码区如果有错误,就会返回所写异常的处理. 首先要清楚,如果没有try的话,出现异常会导致程序崩溃.而try则可以保证程序的正常运行下去,比如说:try{int i = 1/0;}catch(Exception e){........}一个计算的话,如果除数为0,则会报错,如果没有try的话,程序直接崩溃.用try的

【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析

这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try { //需要被检测的异常代码 } catch(Exception e) { //异常处理,即处理异常代码 } 代码区如果有错误,就会返回所写异常的处理. 首先要清楚,如果没有try的话,出现异常会导致程序崩溃.而try则可以保证程序的正常运行下去,比如说: try { int i = 1/0; } catch(Exception e) { ........ } 一个计算的话,如果除数