浅析如何验证fixed关键字效果

开发 后端
在这里作者设置了一个小实验,来验证fixed关键字效果。希望通过本文能对大家有所帮助。

本文主要是一种验证,对与fixed关键字操作的的验证,希望通过本文能让大家对fixed关键字理解得更深入一些。同时也会分析程序员可能出现问题的一些坏习惯,希望对大家有所帮助。

#T#

之前谈到String连接操作的性能,其中会涉及到unsafe操作,而unsafe操作必然会涉及到指针,于是fixed关键字也应运而生。fixed关键字是用来pin住一个引用地址的,因为我们知道CLR的垃圾收集器会改变某些对象的地址,因此在改变地址之后指向那些对象的引用就要随之改变。这种改变是对于程序员来说是无意识的,因此在指针操作中是不允许的。否则,我们之前已经保留下的地址,在GC后就无法找到我们所需要的对象。现在就来我们就来做一个小实验,验证fixed关键字的效果。

当然,这个实验很简单,简单地可能会让您笑话。首先我们来准备一个SomeClass类:

  1. public class SomeClass  
  2. {  
  3.     public int Field;  

然后准备一段代码:

  1. private static unsafe void GCOutOfFixedBlock()  
  2. {  
  3.     var a = new int[100];  
  4.     var c = new SomeClass();  
  5.  
  6.     fixed (int* ptr = &c.Field)  
  7.     {  
  8.         PrintAddress("Before GC", (int)ptr);  
  9.     }  
  10.  
  11.     GC.Collect(2);  
  12.  
  13.     fixed (int* ptr = &c.Field)  
  14.     {  
  15.         PrintAddress("After GC", (int)ptr);  
  16.     }  
  17. }  
  18.  
  19. private static void PrintAddress(string name, int address)  
  20. {  
  21.     Console.Write(name + ": 0x");  
  22.     Console.WriteLine(address.ToString("X"));  

在GCOutOfFixedBlock方法中,我们首先分配一个长度为100的int数组,然后新建一个SomeClass对象。新建数组的目的在于制造“垃圾”,目的是在调用GC.Collect方法时改变SomeClass对象在堆中的位置。由于垃圾回收发生在fixed代码块之外,这样我们前后两次打印出的值便是不同的:

Before GC: 0x1A058C0
After GC: 0x1975DF4

值得注意的是,这段代码必须在Release模式下进行编译,让CLR执行代码时进行优化,这样CLR便会在垃圾回收时发现a数组已经是垃圾了(因为后面的代码不会用它),于是会将其回收——否则便无法看出地址改变的效果来。那么,我们重写一段代码:

  1. private static unsafe void GCInsideFixedBlock()  
  2. {  
  3.     var a = new int[100];  
  4.     var c = new SomeClass();  
  5.  
  6.     fixed (int* ptr = &c.Field)  
  7.     {  
  8.         PrintAddress("Before GC", (int)ptr);  
  9.         GC.Collect(2);  
  10.     }  
  11.  
  12.     fixed (int* ptr = &c.Field)  
  13.     {  
  14.         PrintAddress("After GC", (int)ptr);  
  15.     }  

结果如下:

Before GC: 0x1B558C0
After GC: 0x1B558C0

由于GC发生在fixed代码块内部,因此c对象被pin在堆上了,于是GC前后c对象的地址没变,这就是fixed的作用。那么,下面这段代码运行结果是什么呢?

  1. private static unsafe void Mixed()  
  2. {  
  3.     var a = new int[100];  
  4.     var c1 = new SomeClass();  
  5.     var c2 = new SomeClass();  
  6.  
  7.     fixed (int* ptr1 = &c1.Field)  
  8.     {  
  9.         PrintAddress("Before GC", (int)ptr1);  
  10.     }  
  11.  
  12.     fixed (int* ptr2 = &c2.Field)  
  13.     {  
  14.         PrintAddress("Before GC (fixed)", (int)ptr2);  
  15.         GC.Collect(2);  
  16.     }  
  17.  
  18.     fixed (int* ptr1 = &c1.Field)  
  19.     {  
  20.         PrintAddress("After GC", (int)ptr1);  
  21.     }  
  22.  
  23.     fixed (int* ptr2 = &c2.Field)  
  24.     {  
  25.         PrintAddress("After GC (fixed)", (int)ptr2);  
  26.     }  

至于为什么是这个结果,那便和CLR实现方式有关了。

原文标题:验证fixed关键字效果的小实验

链接:http://www.cnblogs.com/JeffreyZhao/archive/2009/11/29/lab-fixed-keyword.html

责任编辑:彭凡 来源: 博客园
相关推荐

2009-08-13 17:44:34

C# using关键字

2009-06-29 12:58:47

This关键字java

2010-01-26 14:35:11

C++关键字

2009-11-26 19:24:54

PHP类CMS

2012-04-23 13:49:55

PHP技术

2022-01-04 16:35:42

C++Protected关键字

2009-09-17 09:30:00

Linq LET关键字

2009-09-02 09:24:03

C# this关键字

2012-03-01 12:50:03

Java

2018-04-20 15:56:09

Pythonglobal关键字

2009-08-21 14:58:56

C# this关键字

2013-01-30 10:12:14

Pythonyield

2022-05-06 08:32:40

Pythonwith代码

2021-02-01 13:10:07

Staticc语言UNIX系统

2009-08-13 13:04:29

C# lock关键字

2022-06-29 08:05:25

Volatile关键字类型

2022-02-17 08:31:38

C语言staic关键字

2019-11-06 10:36:43

MavenoptionalJava

2021-08-06 07:51:47

关键字int函数

2009-08-26 15:16:29

C# lock关键字
点赞
收藏

51CTO技术栈公众号