淺析如何驗證fixed關鍵字效果
本文主要是一種驗證,對與fixed關鍵字操作的的驗證,希望通過本文能讓大家對fixed關鍵字理解得更深入一些。同時也會分析程序員可能出現(xiàn)問題的一些壞習慣,希望對大家有所幫助。
#T#
之前談到String連接操作的性能,其中會涉及到unsafe操作,而unsafe操作必然會涉及到指針,于是fixed關鍵字也應運而生。fixed關鍵字是用來pin住一個引用地址的,因為我們知道CLR的垃圾收集器會改變某些對象的地址,因此在改變地址之后指向那些對象的引用就要隨之改變。這種改變是對于程序員來說是無意識的,因此在指針操作中是不允許的。否則,我們之前已經(jīng)保留下的地址,在GC后就無法找到我們所需要的對象?,F(xiàn)在就來我們就來做一個小實驗,驗證fixed關鍵字的效果。
當然,這個實驗很簡單,簡單地可能會讓您笑話。首先我們來準備一個SomeClass類:
- public class SomeClass
- {
- public int Field;
- }
然后準備一段代碼:
- private static unsafe void GCOutOfFixedBlock()
- {
- var a = new int[100];
- var c = new SomeClass();
- fixed (int* ptr = &c.Field)
- {
- PrintAddress("Before GC", (int)ptr);
- }
- GC.Collect(2);
- fixed (int* ptr = &c.Field)
- {
- PrintAddress("After GC", (int)ptr);
- }
- }
- private static void PrintAddress(string name, int address)
- {
- Console.Write(name + ": 0x");
- Console.WriteLine(address.ToString("X"));
- }
在GCOutOfFixedBlock方法中,我們首先分配一個長度為100的int數(shù)組,然后新建一個SomeClass對象。新建數(shù)組的目的在于制造“垃圾”,目的是在調(diào)用GC.Collect方法時改變SomeClass對象在堆中的位置。由于垃圾回收發(fā)生在fixed代碼塊之外,這樣我們前后兩次打印出的值便是不同的:
Before GC: 0x1A058C0
After GC: 0x1975DF4
值得注意的是,這段代碼必須在Release模式下進行編譯,讓CLR執(zhí)行代碼時進行優(yōu)化,這樣CLR便會在垃圾回收時發(fā)現(xiàn)a數(shù)組已經(jīng)是垃圾了(因為后面的代碼不會用它),于是會將其回收——否則便無法看出地址改變的效果來。那么,我們重寫一段代碼:
- private static unsafe void GCInsideFixedBlock()
- {
- var a = new int[100];
- var c = new SomeClass();
- fixed (int* ptr = &c.Field)
- {
- PrintAddress("Before GC", (int)ptr);
- GC.Collect(2);
- }
- fixed (int* ptr = &c.Field)
- {
- PrintAddress("After GC", (int)ptr);
- }
- }
結果如下:
Before GC: 0x1B558C0
After GC: 0x1B558C0
由于GC發(fā)生在fixed代碼塊內(nèi)部,因此c對象被pin在堆上了,于是GC前后c對象的地址沒變,這就是fixed的作用。那么,下面這段代碼運行結果是什么呢?
- private static unsafe void Mixed()
- {
- var a = new int[100];
- var c1 = new SomeClass();
- var c2 = new SomeClass();
- fixed (int* ptr1 = &c1.Field)
- {
- PrintAddress("Before GC", (int)ptr1);
- }
- fixed (int* ptr2 = &c2.Field)
- {
- PrintAddress("Before GC (fixed)", (int)ptr2);
- GC.Collect(2);
- }
- fixed (int* ptr1 = &c1.Field)
- {
- PrintAddress("After GC", (int)ptr1);
- }
- fixed (int* ptr2 = &c2.Field)
- {
- PrintAddress("After GC (fixed)", (int)ptr2);
- }
- }
至于為什么是這個結果,那便和CLR實現(xiàn)方式有關了。
原文標題:驗證fixed關鍵字效果的小實驗
鏈接:http://www.cnblogs.com/JeffreyZhao/archive/2009/11/29/lab-fixed-keyword.html