深入解析Go

本书通过 如何研究Go的内部实现、基本数据结构、函数调用协议、Go语言程序的初始化过程、goroutine调度、内存管理、高级数据结构的实现、网络、cgo等几方面对go语言进行深入的剖析。对理解go语言有很大帮助。
具体无序介绍
如何研究Go的内部实现
从源代码安装Go
go语言源代码有plan 9 c 和汇编语言
本书组织结构
基本技巧
阅读源代码
目录分析
bin
go的编译器
src
go语言源代码
//基本工具(编译器)
标准库
pkg
头文件
lib
文档模板
misc
go语言一些工具,葛洪编译器go语言支持,还有cgo雷子
test
go语言单元测试程序
api
包含所有API列表,方便IDE使用
doc
go语言的各种文档,官网上有的这里都有。
使用调试器
go build test.go
gdb test
分析生成的汇编代码
汇编生成
go tool 6g -S hello.go
go tool 6g -h
反汇编
go build test.go
go tool 6l -a test|less
基本数据结构
基本类型
基本类型
结构体和指针
make和new区别
slice
map
底层是用hashMap实现的
初识容量是8,扩容之后回合原来的连接起来。
nil
err指针类型
空指针问题
可以使用reflect包解决
Typeof()
.kind
reflect.Ptr
函数调用协议
Go语言调用汇编和C
Go调用汇编
在GOPATH/src下新建一个add目录
add.go 文件
package add
func Add(a,b uint64)uint64
add_am6.s
汇编代码
子主题 4
Go调用C
add.c文件
#include “runtime.h”
void Add(uint64 a,uint64 b,uint64 ret){ ret = a+b; FLASH(&ret)}
go install add 编译该包
多返回值
c语言是用寄存器来返回值。
go语言是使用栈空间来返回值的。
go关键字
runtime.newproc(size,f,args)
defer关键字
不是原子操作
runtime.deferproc
连续栈
基本原理
Go的runtime都会进行检测,够用继续执行
不够用会出发“中断”,所有上下文都会拷贝到一个新的足够大的栈中。
函数恢复运行时,函数会在新分配的栈中继续运行,就像整个过程都没发生一样。
细节
如何捕获到函数的栈空间不足
旧栈数据复制到新栈
闭包实现
概念
闭包=函数+引用环境
escape analyze
c语言函数内的变量只能在栈上分配
go语言中会自动识别一些情况在堆上分配内存
闭包结构体
Go语言程序初始化过程
Go语言程序初始化过程
编译GDB调试
_rt0_amd64_darwin
main
_rt0_amd64
runtime.check
runtime.args
runtime.osinit
runtime.hashinit
runtime.schedinit
runtime.newproc
runtime.mstart
main.main
runtime.exit
系统初始化
本地线程存储
初始化顺序
调度器初始化
main.main之前准备
sysmon后台任务
scavenger后台任务
goroutine 调度
调度相关数据结构
goroutine的结构体G
uintptr stackguard //分段栈的可用空间下界
uintptr stackbase //分段栈的栈基址
Gobuf sched//进程切换时,利用Sched保存上下文
uintptr stack0
FunVal* fnsrart //goroutine 运行的函数
void* param //用于传递参数,睡眠时其他goroutine设置param,唤醒时此goroutine可以获取
init16 status //状态Gidle 、Grunable、Grunning 、Gsyscall、Gwaiting、Gdead
int64 goid //gorotine 的id号
Gschedlink
M
m // for debuggers, but offset not hard-codeed
uintptr gopc //创建这个goroutine的go的表达式pc
结构体M
Machine的缩写,对应的是操作系统的物理线程。M必须关联P才能执行go代码
结构体P
提高go程序的并发度
Sched
调度实现数据结构
goroutine 的生老病死
goroutine的创建
runtime.newproc(size,f,args)
进入系统调用
goroutine的消亡以及状态的变化
设计和演化
线程池
线程池
任务队列模型
系统调用
协程与保存上下文
Go1.0
Sched结构中atomic字段
Go1.1
processor工作流窃取的调度器
抢占式调度
总体思路
后台有一个检测运行时间的线程,对goroutine 添加一个“标记”。
sysmon
周期性的做epoll操作
切换P
标记P
通知G在合适时机进行调度,尽最大努力送达
morestack的修改
内存管理
go语言带有垃圾回收的语言,大多数情况下不需要用户自己去管理内存
内存池
实现函数tcmalloc库实现
一个带有内存池的分配器,底层直接调用mmap等函数
基本概念
首先向操作系统申请大块内存,自己管理这部分内存
它是一个池子,上层释放的他不会归还操作系统,而是放回池子重复利用。
内存管理必然要考虑碎片化
多线程必须要考虑稳定性和效率问题
扩展知识
首次适应
最佳适应
最差适应
伙伴算法
分配器数据结构
FixAlloc
固定大小(128kB)的对象空闲链分配器,被分配器用于管理存储
MHeap
分配堆,按页的颗粒度进行管理(4KB)
MSpan
一些由MHeap管理的页
MCentral
对于给定尺寸类别的共享free list
MCache
用于小对象的每M一个的cache
垃圾回收
上篇
标记清扫算法
看初始标记的root区域的对象是否有直接或者间接引用
两个阶段
标记阶段:标记和root区域直接或者间接应用到的对象
清除阶段:清除没有标记的对象
位图标记和内存布局
和c语言一样,非侵入式的标记位
16位 特殊位 标记位
16位 垃圾回收 标记位
16位 无指针/块边界 标记位
16位 已分配 标记位
精确的垃圾回收
Mspan结构体
下篇
概念
Go语言垃圾回收的核心函数scanblock。(扫描整个内存区域,得到轻重gc域)
基本标记过程
实现函数
debug_scanblock函数递归实现的
并行垃圾回收
垃圾回收时机
gcpercent控制
高级数据结构实现
channel
first-class的
channel的数据结构
uintgo qcount //队列q中的总数据数量
uintgo dataqsiz //环形队列q数据大小
uint16 elemsize
bool closed
uint8 elemalign
Alg* elemalg //interface for element type
uintgo sendx //发送index
uiintgo recvx //接收index
waitQ recvq //因recv而阻塞的等待队列
waitQ sendq //因send而阻塞的等待队列
Lock
读写channel的操作
实现函数
runtime.chansend函数
runtime.chanrecv函数
select的实现
selectnbrecv(&v,c)
select-case的chan的操作
可以用if-else代替
interface
知识点总结
优势
依赖接口而不是实现
优先使用组合而不是继承
C++一些特性
方法和数据绑在一起。
面向对象应该强调对象间的信息的传递
Eface和Iface
Eface结构体
Type* type
指向具体数据类型指针
类型信息可以实现反射
类型信息结构体
uintptr size
类型大小
uint32 hash
uint8 _unused
uint8 align
uint8 fieldAlign
数据嵌入结构体时对齐
uint8 kind
枚举值,每个类型对应一个编号
Alg* alg
对齐
void* gc
垃圾回收
String string
UncommmonType x
指向一个函数指针数组,收集了整个类型实现所有方法
Type ptrto
void
data
Iface结构体
Itab tab
包含类型信息
数据结构
InterfaceType
inter
Type
type
Itab
link
int32 bad
int32 unused
void (fun[])(void)
多了一个fun[]的方法表。
扩展小知识
Iface中的具体类型中的实现方法会拷贝到Itab的fun数组中
void
data
扩展知识
reflect中的KondOf函数返回的就是interface{}中的Type,该函数最简单是取Eface中的Type域
具体类型向接口类型赋值
编译里面检测接口的方法是不是被实现
三个方法表
Type的UncommonType中有一个方法表,某个具体类型的所有方法都会被收集在这张表中。
reflect的Method
reflect的MethodByName
表中每一项都是一个Method数据结构
String* name
String *pkgPath
Type *mtyp
Type typ
void (ifn)(void)
void (tfn)(void)
Iface中Itab的InterfceType中也有一张方法表,这张表中是接口所声明的方法
表中每一项都是一个 IMethod数据结构
String
name
String
pkgPath
Type type
Iface中的Itab的func域也是一张方法表,这张表的每一项都是一个函数指针,也就是只有实现没有声明。
reflect
TypeOf
valueOf
方法调用
普通方法调用
对象方法调用( func (tv T,a int) int )
T.Mv(7)
T.Mv(t,7)
(T).Mv(t,7)
组合对象方法调用
概念
带有方法的结构体匿名嵌入到另一个结构体中,这个结构体也拥有了嵌入式的方法
接口方法调用
不同之处在于,它根据接口中的方法表,得到对应指针,然后调用的,而前面是直接调用的函数地址。
网络
实现:Go更好的封装了epoll/kqueue,为用户提供了友好式的阻塞接口。Go网络层api优雅的封装
非阻塞io
如何实现
后台poller会不断的进行poll,所有文件描述符都会加载到poller中,当某一时刻一个文件描述符准备好了,poller就会唤醒之前因为它而阻塞的goroutine,于是goroutine重新运行起来。
runtime,main
newm(sysmon,nil)
封装层次
三个层次
依赖系统的api封装
平台独立的runtime封装
提供给用户的库的封装
文件描述符与goroutine
文件描述符与goroutine联系的数据结构 PollDesc
PollDesc
link
Lock
int32 fd
bool closing
uintptr seq
G
rg
Timer wt
int64 wd
cgo
预备知识
cgo关键技术
Go调C
C调Go
内存模型

Xmind思维导图共享
链接:https://pan.baidu.com/s/1lJW9vA5_U7qEKVGQui2kKA
提取码:xa79

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值