go 使用的参数拷贝传递,如果传递的值比较大 注意传递其指针
go 参数传递 使用 值传递, 也就是说传递结构体时候,拷贝结构体的指针,传递结构体指针时候 拷贝的结构体指针
所以对于 只读参数,不进行修改,最好传递结构体指针函数返回的指针被其他使用
)func a() *int {
v :=0
return &v // 导致 局部变量会分配在堆行 不会分配栈上
}
函数的参数是interface{} 函数的实参很可能会逃逸,主要因为interface{} 类型函数往往会使用反射
)fmt.Println(i) // 入参属于interface{} 空接口, 是否有反射查看值是什么类型 逃逸到堆上
过大变量导致的空间不足,超过64KB的变量会逃逸
)// 解决协程的栈空间不足
栈扩容
)2. 解决方式 进行栈扩容,Go的栈初始空间为2KB
3. 在函数调用前判断栈空间morestack
4. 早期使用分段栈(go 1.13) 在逻辑上连接,优点没有空间浪费,栈指针会在不连续的空间跳转,后期 连续栈,缺点 伸缩时候开销大,扩容为原来2倍, 使用比例不足1/4, 变为原来的 1/2
操作系统的虚拟内存:操作系统给应用提供的虚拟的内存的空间,背后也是物理内存或者磁盘
按照需求进行分级分配,runtime.sizeclass.go 进行分配, 总共有68 个级别。
其中 136 个span , mcentral 属于链接头,其中 68个需要GC扫描,其他68个不需要GC扫描。
mcentral 的属于中心索引,使用互斥锁保护,在高并发的场景下 锁冲突严重,参考GMP模型,增加线程的本地缓存。
无指针
– 分配到普通mspan(class 1 - class 67) --将多个微级对象合并成16Byte1. 被栈上的指针引用 2.被全局变量引用 3.被寄存器中指针引用
如何进行并行GC 提升性能?
难点在于如何进行标记阶段,go 语言采用的 三色标记方法
·- 黑色: 表示已经分析扫描,有用
·- 灰色: 有用,还没进行分析扫描 DFS代替队列
·- 白色: 暂时无用
当三色标记结束后只有黑色的对象,下一次开启恢复成 白色
并发标记的问题(删除)-- 在GC时候 进行对象的指针的变动,针对 并发标记问题 使用 Yuasa 删除屏障, 强制将释放的C指针变成灰色,避免 在GC过程中被粗我䣌标记
Yuasa 删除屏障(s释放的指针进行强制为灰色
)
1. 删除屏障可以杜绝在GC标记中删除的问题 ,但是也无法解决并发标记的插入问题
针对插入屏障 使用 Dijkstra 插入屏障
并发标记过程中 将C进行强制置灰,当并发标记过程,新指针指向新的对象,新增的依赖对象 防止错误的GC
混合屏障
系统定时触发
g0 协程内的sysmon 定时检查 ,在2min 内 forcegcperiod 没有过GC,触发,谨慎调整
用户显示触发
调用runtime.gc 并不推荐
申请内存触发
给申请对象的时候伴随着GC
GC优化原则
$env:GODEBUG="gctrace=1"