大綱
達人課
第四部分:執行 編程語言底層之函數執行
第五部分:數據 編程語言底層之數據結構
第七八部分:系統、並發 編程語言底層之系統和並發
開篇:學習基礎技能樹意義
00 學習基礎技能樹意義
- 到底什么是基礎
- 為什么選擇Go作為基礎語言
- 安裝學習環境
- 演示:反匯編、函數內聯優化
第一部分:編譯(編譯、鏈接、可執行文件結構、符號表)
01 編譯
- gcc編譯過程
- go build編譯過程
02 鏈接
- 鏈接器
- 合並方式
- 靜態鏈接和動態鏈接的區別
03 可執行文件結構
- 通用可執行文件結構(COFF)(readelf -h)
- COFF用段(section)存儲不同類型數據(readelf -S)
- 常用段
- 演示:使用readelf、xxd、objdump、gdb查看可執行文件結構信息
- 演示:objcopy -add-section;strip -remove-section;readelf -p
04 符號
- 使用nm查看符號
- 使用readelf -s輸出符號信息
- 刪除符號表對反匯編的影響
- 使用strip刪除符號和調試信息
- 使用UPX壓縮並保護可執行文件
第二部分:內存(虛擬內存、進程內存模型、常量、變量)
05 虛擬內存
- 實模式(8086,boot)與保護模式
- 虛擬存儲器(VM),VA/PA,MMU/TLB,PT/PTE用途
- 缺頁異常(Page Faults),換入換出(swap in/out),顛簸(thrashing)
- 存儲器層次
- 機會主義內存分配
- dstat、pidstat使用示例
06 處理器
- 對稱多處理器(SMP),NUMA的問題
- 物理核心、邏輯核心
- 緩存:L1(d,i)、L2、L3
- 超線程(HT),可能因共享cache造成性能問題
- lscpu使用示例
07 進程內存模型
- 可執行文件和進程的差異
- 進程內存模型
- 使用readelf -l查看段映射
- 使用gdb查看運行期內存模型
08 常量和變量
- 常量和變量的區別
- 常量展開
- 常量陷阱演示
第三部分:指令(初級匯編指令、控制流)
09 初級匯編指令
- 寄存器
- 幾類寄存器
- 內存尋址
- 常用匯編指令
- 操作數長度
- MS-DOS debug
- 簡讀匯編代碼
第四部分:執行(函數執行、調用堆棧、參數及返回值、閉包)
10 調用堆棧
- 調用堆棧call stack
- 堆棧幀stack frame
- 函數調用,現場保護和恢復
- 用GDB查看調用堆棧,輸出堆棧楨信息
- IP寄存器的用途
- 相關匯編指令
11 參數傳遞
- C參數復制,返回值
- Go參數復制,返回值
- 優化模式對參數傳遞的影響
12 if和switch對比
- 是否存在性能差異
- 使用場景
- 反匯編對比
13 死代碼
- 示例
- 使用代碼覆蓋測試檢查
- 查看編譯器能否優化掉死代碼
14 匿名函數
- 匿名函數符號名
- 匿名函數調用方式
- 作為返回值的匿名函數
- 直接調用匿名函數
15 閉包
- 何為閉包
- 閉包通過指針引用環境變量
- 閉包導致環境變量生命周期延長和堆分配
- 閉包怎么調用的
- 閉包與數據競爭
16 遞歸調用
- 什么是遞歸
- Go與C棧大小差異
- 為什么會引起堆棧溢出(stack overflow)
- 什么是尾調用
- 什么是尾遞歸優化
- 為什么go的編譯器對尾遞歸調用不做優化處理
17 延遲調用
- 延遲調用的用途(作用域、IDisposable)
- defer與finally的對比(總能執行)
- 正確理解defer實現和執行機制,確保合理使用
- 利用匿名函數重構作用域
- 性能問題
18 錯誤處理
- 錯誤分類
- 錯誤(異常)是一種“值”,屬於正常邏輯返回(exception,error)
- 使用實例或類型判斷錯誤類別,而非“魔法數字”。(編譯器檢查、重構、常量陷阱)
19 應用
- 阻止GDB調試
- 阻止反匯編、代碼混淆
- monkey patch
- 緩沖區溢出攻擊
第五部分:數據(基礎數據類型、常用數據結構)
20 字符串
- 開篇
- Go字符串和C char*的差異
- 為什么實現為不可變類型
- 拼接字符串實現方式
- 轉換性能優化
21 數組
- 數組值類型和指針差異
- 數組指針和指針數組的差別
- 切片為什么不是動態數組或數組指針
- 用new或make創建引用類型的差別
- 切片和數組的性能差異
22 基於數組實現數據結構
- 開篇
- 棧(Stack)
- 隊列(Queue)
- 緩沖區(Pool)
- 鏈表(Linked List)
23 哈希表
- 開篇
- 哈希表基本實現方式
- 用數組改進鏈表法性能
- 字典的性能調優
- 字典的數據競爭問題
24 結構體
- 匿名字段與繼承
- 名稱遮蔽(成員訪問優先級)
- 結構體內存布局
第六部分:對象(面向對象理論、方法、接口)
25 方法
- 方法與函數的差異
- 方法調用方式,如何傳遞receiver、self、this
- 方法可被內聯嗎
- 匿名字段方法,是繼承調用?還是語法糖?
- 匿名字段方法調用
26 方法集
- 什么是方法集
- 方法集區分基礎類型T和指針類型*T
- 匿名嵌入對方法集的影響
- 方法集調用
27 方法表達式
- 開篇
- Method Expression和Method Value
- 方法表達式實現方式
28 接口
- 什么是接口
- 什么是Duck Type
- 接口實現方式,方法集與接口 和 接口內部結構
- 接口調用與直接調用的性能差異
- 總結
第七部分:並發(進程、線程、協程、通信、同步)
29 進程、線程、協程
- 進程、線程的區別
- 系統線程(內核線程、內核態)和用戶線程的區別
- CPU時間片分配方式
- 協程基本原理,優點和缺點
- 上下文切換(context switch),以及對性能的影響
第八部分:系統(內存管理、垃圾回收、並發調度)
30 內存管理
- 自主實現內存管理
- 內存管理面臨的問題
- Go基於tcmalloc實現的內存分配器工作原理
- 如何釋放物理內存
31 垃圾回收
- 常用方式:引用計數、代齡、標記清理
- 垃圾回收何時啟動?如何避免內存膨脹,避免影響性能?
- Go三色標記+寫屏障模式如何實現並發標記和並發清理?
- 控制器和輔助回收的作用
32 並發調度
- G、M、P模型
- 如何創建Goroutine?
- 如何啟動並發任務?
- 調度器如何執行?
- M/P對應關系
33 連續棧
- 什么是分段棧
- 分段棧的問題是什么
- 連續棧如何實現
- 連續棧回收
- 連續棧擴張問題演示
34 系統監控
- 系統監控的用途
- 強制垃圾回收
- 釋放物理內存
- 搶占調度
- 處理系統調用
- I/O事件
35 通道
- 通道基本原理
- 同步通道和異步通道的區別
- Goroutine Leak
- 架構設計
36 同步
- 常見同步方式
- Mutex、RWMutex、Cond、Semaphore、SpinLock、Atomic區別
- 單核和多核指令是否原子
- HLOCK pin引線(電位拉低、鎖總線)如何實現原子操作
- CAS(Compare-and-swap)
- 用原子操作實現自旋鎖
第九部分:組織(代碼組織方式、訪問權限)
todo
第十部分:動態(反射、動態語言運行模式)
todo
第十一部分:測試(單元測試、性能測試、代碼覆蓋率、數據競爭、性能調優)
todo
第十二部分:工具(GDB調試器、常用工具、Go工具鏈)
todo
