效能優化核心聚焦兩大維度:**記憶體消耗**與**執行速度**。目標是在不犧牲正確性前提下,讓系統跑得更快、完成特定功能所需時間更短。本文以 .NET 平台下的控件產品 MultiRow 為實戰案例,剖析 C# 效能優化的完整方法論與落地技巧。
long start = GC.GetTotalMemory(true);
// 執行待測操作,例如建立 GcMultiRow 實例
var gcMultiRow = new GcMultiRow();
GC.Collect();
GC.WaitForFullGCComplete();
long end = GC.GetTotalMemory(true);
long memoryUsed = end - start;
var watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < 1000; i++) {
gcMultiRow.Sort();
}
watch.Stop();
double avgMs = watch.ElapsedMilliseconds / 1000.0; // 取平均值排除抖動
IL 層級注入 Hook 記錄時間,可快速定位熱點方法。注意:分析時執行速度會較實際運行慢,數據非 100% 精確,需結合其他手段交叉驗證。
針對已知效能敏感模組進行深度審查,確保邏輯以最優路徑執行。
案例:GcMultiRow 百萬行資料的記憶體突圍
100 萬行 × 10 欄 = 1 千萬儲存格,若每格皆為獨立物件將導致記憶體爆炸。解決方案:哈希表稀疏儲存——僅將使用者修改過的行存入 Dictionary<int, RowData>,未修改行共享單一範本物件,大幅降低記憶體佔用。
案例:WPF/Silverlight 平台的虛擬化渲染
SpreadGrid for WPF 採用 VirtualizingPanel:Visual 元素(顯示層)與 Cell 資料模型解耦,僅為可視區域建立 Visual。捲動時回收離螢幕 Visual 供新進入 Cell 復用,數百個 Visual 支撐百萬 Cell。
RowCount)。
// 慢
for (int i = 0; i < gcMultiRow.RowCount; i++) { ... }
// 快
int count = gcMultiRow.RowCount;
for (int i = 0; i < count; i++) { ... }
Brush、Pen 建立/銷毀成本高,用 Dictionary<Color, Brush> 做色值級快取。
public static class GdiPool {
static readonly Dictionary<Color, Brush> _brushes = new();
static readonly Dictionary<Color, Pen> _pens = new();
public static Pen GetPen(Color color) {
if (_pens.TryGetValue(color, out var pen)) return pen;
pen = new Pen(color);
_pens[color] = pen;
return pen;
}
}
// 優化前
public class A { public B _b = new B(); }
// 優化後
public class A {
private B _b;
public B BProp => _b ??= new B();
}
案例:表格排序的改良快速排序
傳統快排在「基本有序」資料(如正序/倒序切換)退化為 O(n²)。MultiRow 採用三支點快排:每次從三個中點選中位數作樞軸,亂序與近乎有序皆非最壞情況,穩定輸出 O(n log n)。
| 操作 | List<T> | Dictionary<TKey, TValue> |
|---|---|---|
| 索引存取 | 快 O(1) | 慢 O(1) 但常數大 |
| 查找 | 慢 O(n) | 快 O(1) |
| 新增 | 快 O(1) 攤銷 | 慢 O(1) 含雜湊計算 |
| 插入/刪除 | 慢 O(n) | 快 O(1) |
StringBuilder,避免 string + string 產生大量中間物件(Save/Load、ASP.NET Render 典型場景)。TryGetValue 替代 ContainsKey + indexer,效能提升 ~2 倍。
// 慢
if (_dic.ContainsKey("Key")) return _dic["Key"];
// 快
if (_dic.TryGetValue("Key", out var val)) return val;
int > string > 自訂類別。自訂 Key 需確保 GetHashCode 低碰撞、Equals 輕量。List.Sort()、BinarySearch() 高度優化,滿足需求優先直用。
var list = new List<int> { 3, 10, 15 };
list.BinarySearch(10); // 回傳 1
list.BinarySearch(8); // 回傳 -2(補碼表示插入位置)
ThreadPool,主執行緒保持響應。需謹慎處理跨執行緒存取與死鎖(雙重檢查鎖定模式)。Control.Refresh() 設 Invalidate 標記非同步重繪;BeginInvoke() 發佈自訂非同步動作。當上述手段仍無法秒級完成時,進度條、Loading 動畫、友善提示文字(「操作可能需較久,請稍候」)能有效緩解使用者焦慮。
作者簡介: 胡森,葡萄城軟體工程師,PowerTools 產品線專案經理。長期專注 .NET UI 控件架構設計與效能極限優化,致力為開發者提供高效、易用的企業級控件。