Array 是 .NET 中最基礎的集合結構,雖然語法簡單,但其記憶體配置、型別系統交互與 JIT 編譯器優化策略卻蘊含許多進階細節。本文將從陣列大局觀、零基與非零基陣列、多維與交錯陣列、以及不安全程式碼優化等面向,系統性探討 C# 陣列的核心機制與效能考量。
陣列是參考型別,實例永遠配置在 Managed Heap 上,變數本身僅存放參考指標。元素型別分為實值型別與參考型別:
int 為 0,DateTime 為 DateTime.MinValue)。null,需另行 new 實體。int[] intArr = new int[3]; // {0, 0, 0}
DateTime[] dtArr = new DateTime[3]; // {MinValue, MinValue, MinValue}
string[] strArr = new string[3]; // {null, null, null}
C# 預設建立的陣列皆為零基(Lower Bound = 0),對應 IL 指令 newarr,JIT 編譯器會進行積極優化:迴圈存取時僅在進入前檢查一次邊界,後續不再重複檢查,效能極高。
透過 Array.CreateInstance 可建立任意下限的陣列:
Array arr = Array.CreateInstance(typeof(int), new[] {5}, new[] {1}); // 索引 1~5
Console.WriteLine(arr.GetLowerBound(0)); // 1
Console.WriteLine(arr.GetUpperBound(0)); // 5
非零基陣列型別為 System.Int32[*](含星號),而非 System.Int32[]。每次存取皆需檢查上下界,JIT 無法優化,效能顯著低於零基陣列。
| 特性 | 多維陣列 int[,] | 交錯陣列 int[][] |
|---|---|---|
| 記憶體分佈 | 單一連續區塊 | 陣列的陣列,多個獨立區塊 |
| 建立/銷毀成本 | 一次配置,較低 | 需配置 N+1 個陣列物件,GC 壓力大 |
| 存取檢查 | 每次檢查兩個索引,無特殊優化 | 若內層為零基陣列,單層檢查即可 |
| 適用場景 | 一次建立、一次遍歷(如矩陣運算) | 一次建立、多次隨機存取(如稀疏矩陣) |
fixed) 繞過邊界檢查unsafe static void Main()
{
int[,] matrix = new int[3, 3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
matrix[i, j] = i * 3 + j;
fixed (int* p = &matrix[0, 0])
{
for (int i = 0; i < 3; i++)
{
int baseOffset = i * 3;
for (int j = 0; j < 3; j++)
Console.WriteLine(p[baseOffset + j]); // 直接指標運算
}
}
}
fixed 關鍵字鎖定陣列在 Managed Heap 上的位置,防止 GC 移動記憶體導致指標失效。
unsafe static void Main()
{
int* arr = stackalloc int[10]; // 無 GC、無物件頭、極快
for (int i = 0; i < 10; i++) arr[i] = i;
for (int i = 0; i < 10; i++) Console.WriteLine(arr[i]);
}
適用於極小、生命週期極短、效能敏感的情境(如高頻數學運算),但需謹慎使用以免 Stack Overflow。
unsafe / stackalloc,並嚴格限制範圍、加註釋。