成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解.NET數組的前世今生

開發 后端
在這里我們將把.NET數組講透,包括多維數組和交錯數組,希望對大家了解Array有所幫助。

Array也就是數組,本文將為大家講述的是.NET數組的前生今世,希望通過本文能為大家講透.NET數組。以及數組的具體使用方法。

1. 數組大局觀

數組是一個引用類型,也就是意味著數組的內存分配在托管堆上,并且我們在棧上維護的是他的指針而并非真正的數組。

接下來我們分析下數組的元素,其中的元素無外乎是引用類型和值類型。

當數組中的元素是值類型時,,不同于int i;這樣的代碼。數組會根據數組的大小自動把元素的值初始化為他的默認值。例如:

  1. static void Main(string[] args)  
  2. {  
  3.     int[] intArray = new int[3];  
  4.     foreach(int i in intArray)  
  5.     {  
  6.         Console.WriteLine(i);  
  7.     }  
  8.     DateTime[] dtArray = new DateTime[3];  
  9.     foreach (DateTime i in dtArray)  
  10.     {  
  11.         Console.WriteLine(i);  
  12.     }  

結果如下:

結果

當數組中的元素是引用類型時,實際上數組中的元素是一個指向對象實際內存空間的指針,占用4Bytes的空間。

2. 談談零基數組

從學C語言時起,相信老師就會對我們講,數組的***個索引是0,而不是1。但是在C#中,我們可以去構造一個非零基數組,在這一節,我們就來把這個說透。

在常規意義上,我們初始化一個數組,都默認是零基數組,這也使得數組成為了字符串后再一個初始化時特殊的類型。正如我們知道的一樣,初始化一個字符串時,對應的IL指令是newstr,同樣,初始化一個零基數組對應的IL指令是newarr。

當我們希望構造一個非零基數組時,我們可以以下的語句來做到:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine(intArr.GetValue(1).ToString());  
  5.     Console.WriteLine(intArr.GetValue(0).ToString());  

得到的測試結果便如下:

測試結果

于是便證明,我們初始化了一個非零基數組。此外,延伸一下,我們還應該通過這個記住以下兩個方法:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine(intArr.GetLowerBound(0));  
  5.     Console.WriteLine(intArr.GetUpperBound(0));  

得到的測試結果如下:

測試結果

3. 談談效率問題

相信會有好多陰謀論者說,C#是個類型安全的語言,也就是意味著我循環時每次訪問一次數組的元素,那么就要檢查一次該索引是否會造成數組越界,于是就造成了一定的性能損失。那么在這里,我們就把這個問題說透。

我們在這里把數組分成零基數組,非零基數組,多維數組,交錯數組四種情況來分別討論這個問題。

零基數組是.NET中提倡使用的類型,并且初始化時提供了特殊的IL指令newarr則充分說明了他在.NET中的特殊性,自然.NET Framework也會為其提供很大的優化待遇。在循環訪問數組時,如這樣的代碼:

  1. static void Main(string[] args)  
  2. {  
  3.     int[] intArr = new int[5];  
  4.     for (int i = 0; i < 4; i++)  
  5.     {   
  6.         //Some Method  
  7.     }  

JIT編譯器只會在循環開始之前檢查一次4和intArr.GetUpperBound的大小關系,之后便不會對其進行干預。也就是說JIT編譯器只對其檢查一次安全,因此帶來的性能損失是非常小的。

而對于非零基數組,我們來比較這樣兩段代碼:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine(intArr.GetValue(1).ToString());  
  5.     Console.WriteLine(intArr.Length);  
  6.     //  
  7.     int[] intArr1 = new int[5];  
  8.     Console.WriteLine(intArr1[1]);  
  9.     Console.WriteLine(intArr1.Length);  

其實兩者創建的幾乎是相同的數組,調用的也幾乎是一樣的方法,但是我們看下IL卻會發現兩者有著驚人的不同,首先是非零基數組的IL:

非零基數組的IL

接下來是零基數組的:

零基數組

我們可以發現,對于非零基數組中的大部分操作,.NET Framework都提供了對應的IL指令,我們也可以理解為.NET Framework為其提供了特殊的優化。

當然,實際上,正如CLR via C#所說的一樣:.NET Framework對應非零基數組沒有任何方面的優化,每次訪問都需要檢查其上限和下限與索引之間的關系。效率的損耗是必然的。

事實上,當我們測試這樣一段代碼時,也會發現其實零基數組和非零基數組的區別是很大的:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine("intArr的?類à型í是?:o{0}", intArr.GetType());   
  5.     //  
  6.     int[] intArr1 = new int[5];  
  7.     Console.WriteLine("intArr1的?類à型í是?:o{0}", intArr1.GetType());   

得到的結果如下:

結果

接下來我們再來簡單地說下多維數組和交錯數組。

多維數組和非零基數組一樣,都沒有受到.NET Framework的特殊優待。

而交錯數組,其實就是數組中的數組,因此效率實際上取決于數組中的數組是零基數組還是非零基數組。

那接下來的一節,我們來具體探討一下交錯數組和多維數組的區別和應用。

4. 多維數組和交錯數組

考慮到兩個詞的翻譯問題,在這里給出兩個詞的英文:

多維數組:Multi-dimensional Array。

交錯數組:Jagged Array。

好,下面步入正題。

首先從二者的內存分布說起。

多維數組是一個整體的數組,因此他在內存中占據一個整體的托管堆內存塊。

而交錯數組實際上是數組中的數組,因此我們用二維交錯數組來舉例,其內存如圖所示:

內存圖

也就是說,如果是一個3*100的數組,也就是說需要初始化101次數組,當數組的元素更加多的時候,那創建和垃圾回收將帶來巨大的效率損失。

因此,也就是說:交錯數組的效率瓶頸在于創建和銷毀上,而并非類型安全檢查上。

于是,我們就可以得出這樣的結論:

當一次創建,多次訪問時,我們應該創建交錯數組。

當一次創建,一次訪問時,我們應該創建多維數組。

5. 用代碼改善效率

上面說到了,訪問非零基數組和多維數組的效率是比較低的,對于非零基數組,我們的應用比較少,但是多維數組,相信每個人都或多或少有著一定的應用,那么面對其性能問題,我們該怎么辦呢?

我們先來想想,多維數組的訪問,性能瓶頸在安全檢查上。在C語言中,為什么沒有這樣的問題,對,因為C語言不會做這樣的檢查。于是,相信聰明的大家都會想到不安全代碼。

改善多維數組以及非零基數組的效率問題,我們就用不安全代碼。

  1. static unsafe void Main(string[] args)  
  2. {  
  3.     int[,] intArr = new int[3, 3];  
  4.     for (int i = 0; i < 3; i++)  
  5.     {  
  6.         for (int j = 0; j < 3; j++)  
  7.         {  
  8.             intArr[i, j] = i * 3 + j;  
  9.         }  
  10.     }  
  11.     fixed (int* p = &intArr[0, 0])  
  12.     {  
  13.         for (int i = 0; i < 3; i++)  
  14.         {  
  15.             int baseOffset = i * 3;  
  16.             for (int j = 0; j < 3; j++)  
  17.             {  
  18.                 Console.WriteLine(baseOffset + j);  
  19.             }  
  20.         }  
  21.     }  

這里,我們又見到了C語言中熟悉的指針,相信不需要多加介紹了。這里唯一需要注意的就是fixed,由于在垃圾回收時采用的是代機制+壓縮機制,因此其內存地址很可能發生改變,因此我們應該講數組的內存地址鎖住,防止我們訪問到其他的內存地址而造成我們讀取數據的錯誤。

6. 對零基數組的精益求精

當然,即使是零基數組,我們依然在托管堆上為其分配了內存空間。如果對性能要求極高,我們知道創建一個對象也是有著一定的時間損耗,其中包括分配內存空間,同步塊索引,以及指向下一塊內存空間的指針等一系列復雜的操作。那么我們就放棄掉托管堆這個東東,而直接在棧中來創建這個數組,這樣又省去了很多時間,從而達到了和C語言相同的效果,代碼如下:

  1. static unsafe void Main(string[] args)  
  2. {  
  3.     int* intArr=stackalloc int[10];  
  4.     for (int i = 0; i < 10; i++)  
  5.     {  
  6.         intArr[i] = i;  
  7.     }  
  8.     for (int i = 0; i < 10; i++)  
  9.     {  
  10.         Console.WriteLine(intArr[i]);  
  11.     }  

這樣,效率就進一步提高了,對于二維數組,我們一樣可以如此創建。其代碼與C語言完全等同。我在這里就不繼續演示了。

7. 總結

在全文中,主要是對數組的各個方面做一個比較簡略地介紹,其中包括數組的基礎知識,分類,以及效率性能問題,***就是用不安全代碼來訪問創建數組來提高性能。

不過***說一句,在實際工作中,如果對性能沒有特別高的要求,則沒必要用不安全代碼來操作數組,因為其很可能因為你的一些失誤而帶來其他的一些安全問題,并且對代碼的可讀性也是個比較大的傷害,這就有些得不償失了。

【編輯推薦】

  1. C#數組基礎介紹與操作詳解
  2. 淺析C#數組初始化性能測試
  3. C#數組操作詳細剖析
  4. 淺析C#數組操作方法
  5. C#數組和串操作經驗總結
責任編輯:彭凡 來源: 博客園
相關推薦

2011-08-23 09:52:31

CSS

2015-11-18 14:14:11

OPNFVNFV

2014-07-30 10:55:27

2025-02-12 11:25:39

2014-07-21 12:57:25

諾基亞微軟裁員

2019-06-04 09:00:07

Jenkins X開源開發人員

2014-07-15 10:31:07

asyncawait

2016-12-29 18:21:01

2021-06-17 07:08:19

Tapablewebpack JavaScript

2016-12-29 13:34:04

阿爾法狗圍棋計算機

2012-05-18 16:54:21

FedoraFedora 17

2013-05-23 16:23:42

Windows Azu微軟公有云

2016-11-03 13:33:31

2016-11-08 19:19:06

2021-04-15 07:01:28

區塊鏈分布式DLT

2011-05-13 09:43:27

產品經理PM

2015-06-11 11:10:09

對象存儲云存儲

2019-08-05 10:08:25

軟件操作系統程序員

2013-11-14 16:03:23

Android設計Android Des

2019-04-28 09:34:06

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品视频网 | 欧美一区免费 | 中文字幕一区二区三区在线观看 | 91在线观看网址 | 日日摸天天添天天添破 | 91日日| 99热视| 国产高清久久久 | 欧美性网 | 成人av免费 | 天堂综合 | 久久综合狠狠综合久久 | 欧美成人一区二区三区 | 91热在线| 伊人狠狠干 | 国产高清久久 | 中文字幕视频一区二区 | 久久精品网| 欧美一级α片 | 成人在线免费视频观看 | 九热在线| 欧美视频1区 | 91精品久久久久久久久久 | 51ⅴ精品国产91久久久久久 | 国产亚洲久 | 亚洲一区二区三区在线 | 99精品在线观看 | 日本爱爱 | 亚洲+变态+欧美+另类+精品 | 看特级黄色片 | av天天干| 欧美一区二区成人 | 91欧美激情一区二区三区成人 | 亚洲精品国产一区 | 国产视频欧美 | 国产一区久久久 | 国产免费又黄又爽又刺激蜜月al | 日日日日日日bbbbb视频 | 午夜欧美 | 免费久久视频 | 久久不卡区 |