大纲
达人课
第四部分:执行 编程语言底层之函数执行
第五部分:数据 编程语言底层之数据结构
第七八部分:系统、并发 编程语言底层之系统和并发
开篇:学习基础技能树意义
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