內容簡介
了解.NET記憶體管理的內部工作原理、陷阱和技術,以便有效地避免軟體中出現各種性能和可伸縮性問題。儘管.NET具有自動記憶體管理功能,但了解 .NET的記憶體管理工作原理以及如何*好地編寫與之高效互動的軟體方面仍有許多益處。《.NET記憶體管理寶典 提高代碼質量、性能和可擴展性》是你通過了解和處理 .NET 中的記憶體管理來編寫出更好軟體的全面指南。 《.NET記憶體管理寶典 提高代碼質量、性能和可擴展性》經過了 Microsoft 的 .NET 團隊全面審查,包含 了25 個有價值的故障排除方案,旨在幫助診斷具有挑戰性的記憶體問題。讀者還將受益於多個 .NET 記憶體管理”規則”,這些規則介紹了編寫記憶體感知代碼的方法以及避免常見的破壞性陷阱的方法。 本書內容 ● 了解自動記憶體管理的理論基礎 ● 深入研究.NET記憶體管理的各個方面,包括對垃圾回收(GC)實現的詳細介紹,這些知識如果自行摸索需要多年經驗才能獲得 ● 獲得如何將這些知識套用於實際軟體開發中的實用建議 ● 使用與 .NET 記憶體管理相關工具的實用知識來診斷各種與記憶體相關的問題 ● 探索高級記憶體管理的各個方面,包括使用Span和Memory類型。
本書內容包括了解自動記憶體管理的理論基礎,深入研究.NET記憶體管理的各個方面,包括對垃圾回收(GC)實現的詳細介紹。
圖書目錄
第1章 基本概念 1
1.1 記憶體相關術語 2
1.1.1 靜態分配 6
1.1.2 暫存器機 6
1.1.3 堆疊(Stack) 7
1.1.4 堆疊機 11
1.1.5 指針 12
1.1.6 堆(Heap) 14
1.2 手動記憶體管理 15
1.3 自動記憶體管理 19
1.4 引用計數 23
1.5 跟蹤回收器(Tracking Collector ) 26
1.5.1 標記階段 27
1.5.2 回收階段 30
1.6 小歷史 32
1.7 本章小結 34
規則1 – 自學 34
第2章 底層記憶體管理 37
2.1 硬體 37
2.1.1 記憶體 42
2.1.2 CPU 43
2.2 作業系統 55
2.2.1 虛擬記憶體 55
2.2.2 large page 59
2.2.3 虛擬記憶體碎片 59
2.2.4 通用記憶體布局 59
2.2.5 Windows記憶體管理 60
2.2.6 Windows記憶體布局 65
2.2.7 Linux記憶體管理 67
2.2.8 Linux記憶體布局 68
2.2.9 作業系統的影響 69
2.3 NUMA和CPU組 70
2.4 本章小結 71
規則2 – 避免隨機訪問,擁抱循序訪問 71
規則3 – 提高空間和時間數據局部性 72
規則4 – 不要放棄使用更高級技巧的可能性 72
第3章 記憶體測量 73
3.1 儘早測量 74
3.1.1 開銷和侵入性 74
3.1.2 採樣與跟蹤 75
3.1.3 調用樹 75
3.1.4 對象圖 76
3.1.5 統計 77
3.1.6 延遲與吞吐量 79
3.1.7 記憶體轉儲、跟蹤、實時調試 80
3.2 Windows環境 81
3.2.1 概述 81
3.2.2 VMMap 81
3.2.3 性能計數器 82
3.2.4 Windows事件跟蹤 87
3.2.5 Windows性能工具包 95
3.2.6 PerfView 104
3.2.7 ProcDump, DebugDiag 111
3.2.8 WinDbg 112
3.2.9 反彙編程式和反編譯程式 114
3.2.10 BenchmarkDotNet 114
3.2.11 商業工具 115
3.3 Linux環境 123
3.3.1 概況 123
3.3.2 Perfcollect 124
3.3.3 Trace Compass 126
3.3.4 記憶體轉儲 134
3.4 本章小結 135
規則5 – 儘早測量GC 137
第4章 .NET基礎知識 139
4.1 .NET版本 139
4.2 .NET內部原理 141
4.3 程式集和應用程式域 148
4.4 進程記憶體區域 150
4.4.1 場景4-1:我的程式占用了多大記憶體 153
4.4.2 場景4-2:我的程式的記憶體使用率持續攀升(1) 155
4.4.3 場景4-3:我的程式的記憶體使用率持續攀升(2) 157
4.4.4 場景4-4:我的程式的記憶體使用率持續攀升(3) 158
4.5 類型系統 161
4.5.1 類型的分類 161
4.5.2 類型的存儲 162
4.5.3 值類型 163
4.5.4 引用類型 169
4.6 字元串 173
4.6.1 字元串暫存 178
4.6.2 場景4-5:我的程式的記憶體使用率太高 182
4.7 裝箱與拆箱 185
4.8 按引用傳遞 188
4.8.1 按引用傳遞值類型實例 188
4.8.2 按引用傳遞引用類型實例 189
4.9 類型數據局部性 190
4.10 靜態數據 193
4.10.1 靜態欄位 193
4.10.2 靜態數據揭秘 194
4.11 本章小結 197
規則6 – 測量你的程式 197
規則7 – 不要假設記憶體泄漏不存在 198
規則8 – 考慮使用結構 198
規則9 – 考慮使用字元串暫存 198
規則10 – 避免裝箱 198
第5章 記憶體分區 201
5.1 分區策略 201
5.2 按大小分區 202
5.2.1 小對象堆 203
5.2.2 大對象堆 203
5.3 按生存期分區 207
5.3.1 場景5-1:我的程式健康嗎?
實時的代大小 210
5.3.2 記憶集 214
5.3.3 卡表(Card Tables) 218
5.3.4 卡包(Card Bundles) 222
5.4 按物理分區 224
5.4.1 場景5-2:nopCommerce可能發生記憶體泄漏 229
5.4.2 場景5-3:大對象堆浪費了 236
5.4.3 段和堆解析 237
5.4.4 段重用 239
5.5 本章小結 241
規則11 – 監視代大小 241
規則12 – 避免不必要的堆引用 241
規則13 – 監視段使用情況 242
第6章 記憶體分配 243
6.1 記憶體分配簡介 243
6.2 bump pointer分配 244
6.3 空閒列表分配 250
6.4 創建新對象 253
6.4.1 小對象堆分配 255
6.4.2 大對象堆分配 257
6.5 堆再平衡 260
6.6 OutOfMemoryException異常 262
場景6-1:OutOfMemoryException異常 263
6.7 堆疊分配 265
6.8 避免分配 266
6.8.1 顯式的引用類型分配 267
6.8.2 隱式的分配 286
6.8.3 類庫中的各種隱式分配 293
6.8.4 場景6-2:調查程式中的分配情況 297
6.8.5 場景6-3:Azure Functions 299
6.9 本章小結 300
規則14 – 在性能攸關的地方,
避免堆分配 300
規則15 – 避免過多的LOH分配 301
規則16 – 如果可行,在堆疊上分配 301
第7章 垃圾回收——簡介 303
7.1 高層視圖 303
7.2 GC過程的示例 304
7.3 GC過程的步驟 309
場景7-1:分析GC的使用情況 309
7.4 分析GC 313
7.5 垃圾回收性能調優數據 314
7.5.1 靜態數據 314
7.5.2 動態數據 315
7.5.3 場景7-2:了解分配預算 317
7.6 回收觸發器 325
7.6.1 分配觸發器 326
7.6.2 顯式觸發器 326
7.6.3 場景7-3:分析顯式GC調用 328
7.6.4 低記憶體級別系統觸發器 333
7.6.5 各種內部觸發器 333
7.7 EE掛起 334
場景7-4:分析GC掛起時間 335
7.8 要判決的代 336
場景7-5:被判決的代的分析 338
7.9 本章小結 339
第8章 垃圾回收——標記階段 341
8.1 對象的遍歷與標記 341
8.2 局部變數根 342
8.2.1 局部變數存儲 343
8.2.2 堆疊根 343
8.2.3 詞法作用域 343
8.2.4 存活堆疊根與詞法作用域 344
8.2.5 帶有激進式根回收的存活堆疊根 345
8.2.6 GC信息 350
8.2.7 固定局部變數 354
8.2.8 堆疊根掃描 356
8.3 終結根 357
8.4 GC內部根 357
8.5 GC句柄根 358
8.6 處理記憶體泄漏 363
8.6.1 場景8-1:nopCommerce可能
發生記憶體泄漏 365
8.6.2 場景8-2:找出常出現的根 367
8.7 本章小結 369
第9章 垃圾回收——計畫階段 371
9.1 小對象堆 371
9.1.1 插頭和間隙 371
9.1.2 場景9-1:具有無效結構的
記憶體轉儲 375
9.1.3 磚表 376
9.1.4 固定 377
9.1.5 場景9-2:調查固定 381
9.1.6 代邊界 385
9.1.7 降級 385
9.2 大對象堆 389
9.3 壓縮的決策 390
9.4 本章小結 391
第10章 垃圾回收——清除和壓縮 393
10.1 清除階段 393
10.1.1 小對象堆 393
10.1.2 大對象堆 394
10.2 壓縮階段 394
10.2.1 小對象堆 394
10.2.2 大對象堆 397
10.2.3 場景10-1:大對象堆的碎片化 398
10.3 本章小結 404
規則17 – 觀察運行時掛起 405
規則18 – 避免“中年危機” 406
規則19 – 避免老的代和LOH碎片化 406
規則20 – 避免顯式GC 407
規則21 – 避免記憶體泄漏 407
規則22 – 避免固定 407
第11章 GC風格 409
11.1 模式概述 409
11.1.1 工作站模式與伺服器模式 409
11.1.2 非併發模式與併發模式 411
11.2 模式配置 411
11.2.1 .NET Framework 412
11.2.2 .NET Core 412
11.3 GC停頓和開銷 413
11.4 模式描述 414
11.4.1 非並發工作站模式 415
11.4.2 並發工作站模式(4.0版本之前) 416
11.4.3 後台工作站模式 417
11.4.4 非並發伺服器模式 423
11.4.5 後台伺服器模式 425
11.5 延遲模式 426
11.5.1 批處理模式 426
11.5.2 互動式模式 426
11.5.3 低延遲模式 427
11.5.4 持續低延遲模式 427
11.5.5 無GC區域模式 429
11.5.6 延遲最佳化目標 430
11.6 選擇GC風格 431
11.6.1 場景11-1:檢查GC設定 432
11.6.2 場景11-2:對不同GC模式進行基準測試 433
11.7 本章小結 438
規則23 – 有意識地選擇GC模式 439
規則24 – 記住延遲模式的相關知識 439
第12章 對象生存期 441
12.1 對象與資源的生命周期 441
12.2 終結 442
12.2.1 簡介 443
12.2.2 激進式根回收問題 446
12.2.3 關鍵終結器 449
12.2.4 終結的內部實現 449
12.2.5 場景12-1:由於終結而導致的記憶體泄漏 455
12.2.6 復活(Resurrection) 460
12.3 Disposable對象 463
12.4 安全句柄 468
12.5 弱引用 473
12.5.1 快取 477
12.5.2 弱事件模式 479
12.5.3 場景12-2:由於事件導致的記憶體泄漏 484
12.6 本章小結 486
規則25 – 避免終結器 486
規則26 – 顯式清理 487
第13章 其他主題 489
13.1 依賴句柄 489
13.2 執行緒局部存儲 494
13.2.1 執行緒靜態欄位 494
13.2.2 執行緒數據插槽 497
13.2.3 執行緒局部存儲的內部 498
13.2.4 使用場景 503
13.3 託管指針 504
13.3.1 ref局部變數 505
13.3.2 ref返回值 505
13.3.3 唯讀ref變數和in參數 507
13.3.4 ref類型的內部 511
13.3.5 C#中的託管指針——ref變數 521
13.4 關於結構的更多知識 526
13.4.1 唯讀結構 526
13.4.2 ref結構(類似於託管指針的類型) 528
13.4.3 固定大小的緩衝區 529
13.5 對象/結構布局 533
13.6 非託管約束 541
13.7 本章小結 546
第14章 高級技巧 547
14.1 Span和Memory 547
14.1.1 Span 547
14.1.2 Memory 560
14.1.3 IMemoryOwner 562
14.1.4 Memory的內部實現 566
14.1.5 Span和Memory使用準則 568
14.2 Unsafe 568
14.3 面向數據設計 573
14.3.1 戰術型設計 574
14.3.2 戰略型設計 576
14.4 未來特性 585
14.4.1 可為空引用類型 585
14.4.2 Pipelines 590
14.5 本章小結 595
第15章 編程API 597
15.1 GC API 597
15.1.1 收集數據和統計 597
15.1.2 GC通知 604
15.1.3 控制非託管記憶體壓力 606
15.1.4 顯式回收 606
15.1.5 無GC區域 606
15.1.6 終結(Finalization)管理 606
15.1.7 記憶體使用率 607
15.1.8 GC類中的內部調用 608
15.2 CLR Hosting 609
15.3 ClrMD 616
15.4 TraceEvent庫 621
15.5 自定義GC 623
15.6 本章小結 626
作者簡介
Konrad Kokosa是一位經驗豐富的軟體設計師和開發人員。他對Microsoft公司的技術特別感興趣,同時對其他所有技術也充滿好奇。Konrad從事編程工作已經有十多年,解決過.NET世界中的許多性能問題和架構難題,設計和提升過.NET應用程式的運行速度。他是一名獨立顧問,是meetup和技術會議講師,喜歡寫Twitter。Konrad還分享了他作為.NET領域培訓講師的激情歲月,特別是在應用程式性能、編碼優秀實踐和診斷方面。他是華沙Web性能小組的創始人。他是Visual Studio和開發工具類別中的Microsoft MVP。他是Dotnetos.org的聯合創始人。Dotnetos.org由三位.NET愛好者發起,主要組織.NET性能相關的會議。譯 者 簡 介, 葉偉民《.NET並發編程實戰》的譯者。曾在美國舊金山工作,具有16年的.NET開發經驗,目前從業於金融科技行業。塗曙光,前微軟技術專家,專注於.NET和JavaScript技術領域。目前在私募基金行業從事低延遲交易系統的開發。