開發環境測試通過,上線卻頻傳 Timeout、記憶體暴漲、CPU 100%、回應緩慢。這四大「隱形殺手」在新手與資深開發者身上反覆上演,本文逐一拆解根因與修正模式。
Public Shared Function GetData() As DataTable
Dim conn As New SqlConnection(connStr)
conn.Open() ' 開啟
Dim cmd As New SqlCommand(sql, conn)
Dim dt As New DataTable()
dt.Load(cmd.ExecuteReader())
Return dt ' 忘記 conn.Close() / Dispose()
End Function
// C# 推薦
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
var dt = new DataTable();
dt.Load(reader);
return dt;
}
} // 自動 Dispose → 關閉連線、歸還池
// VB.NET
Using conn As New SqlConnection(connStr)
Using cmd As New SqlCommand(sql, conn)
conn.Open()
Using reader = cmd.ExecuteReader()
Dim dt As New DataTable()
dt.Load(reader)
Return dt
End Using
End Using
End Using
DataTable、DataSet、DataReader、DataAdapter、SqlConnection、FileStream、GDI+ 物件、COM 物件 等實作 IDisposable 的類別。
Dim dt As New DataTable() ' 迴圈內重複 new,舊物件成 Gen 2 垃圾
For Each row In rows
dt = GetDataTable() ' 未 Dispose
Process(dt)
Next
// 迴圈外建立、迴圈內重用、最後 Dispose
var dt = new DataTable();
try {
foreach (var row in rows) {
dt.Clear();
FillDataTable(dt, row);
Process(dt);
}
} finally {
dt.Dispose();
}
// 或每次 using (較簡潔,效能略低)
foreach (var row in rows) {
using (var dt = new DataTable()) {
FillDataTable(dt, row);
Process(dt);
}
}
IDisposable → 必須 Dispose() 或 using。Dispose() 放在 finally 區塊,異常時也能釋放。Clear() 重用。For Each 比 for i=0 to Count-1 效率更高(避免索引器多次呼叫)。<compilation debug="true">Debug 模式:
- 不優化 JIT 碼、保留完整 PDB 符號、啟用編輯繼續。
- 批次編譯關閉 → 每個頁面獨立組件 → 組件數暴增。
- 腳本/資源不快取、ViewState 不加密壓縮。
- 記憶體佔用可達 Release 模式 3-5 倍。
Configuration: Release
Platform: Any CPU / x64
刀片伺服器 32GB RAM,部署 Debug 版本 → 2 天記憶體飆至 2.5GB → IIS 回收才緩解。改 Release + debug=false → 穩定在 1.2GB。
DataTable/DataSet 未釋放、大物件堆積 (LOH) 碎片化。using、定期 GC.Collect()(僅限長時間運行服務)、改用 SqlDataReader 流式處理。Private Memory Limit = 1.5GB、Queue Length = 5000、Idle Timeout = 0。Web Garden (多 Worker Process) 分散載入。Private Memory Limit 防止佔盡實體 RAM。w3wp.exe = 獨立記憶體空間。| 檢查項目 | 正確做法 |
|---|---|
| 資料庫連線 | using 區塊 / try-finally Dispose |
| IDisposable 物件 | 全面 using,迴圈外重用大物件 |
| Web.config debug | false |
| 建置配置 | Release |
| AppPool 記憶體限制 | 設定 Private Memory Limit (建議 1.5-2GB) |
| 長時間服務 | 定期 GC.Collect()、監控 LOH |
| 資料庫查詢 | 參數化、索引、非同步、連線池大小調優 |
這四大錯誤本質上都是「資源管理不當」與「環境配置疏忽」。養成 using 肌肉記憶、上線前跑一次 Release Build 檢查清單、建立 APM 監控基準線,即能消除 90% 的上線驚魂。工程品質,始於細節。