相信不少人在這樣或那樣的項目中,或者無心間看到了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說明:
結合上面的理論,若是還能輸出結果說明指針操做成功,沒有由於GC的回收形成指針操縱了不正確的地址,由於fixed語句塊釘住了ints變量,禁止垃圾回收器操做內存地址,重定位可移動變量。爲何要這樣作呢?咱們不是能夠用託管代碼直接操做數組嗎?
沒錯,但你別忘了指針操做數組是很快的,由於它會關閉數組索引的檢查即關閉索引的上下限檢查,這樣的好處是:你的程序是性能優先,以性能爲核心的時候這反而是最佳的解決方案!