golang 栈的扩大和收缩
来源:互联网 发布:mac磁盘怎么看空间 编辑:程序博客网 时间:2024/06/05 14:38
栈扩大
stack.go中的常量,用于检查goroutinue的状态
uintptrMask = 1<<(8*sys.PtrSize) - 1 // Goroutine preemption request. // Stored into g->stackguard0 to cause split stack check failure. // Must be greater than any real sp. // 0xfffffade in hex.stackPreempt = uintptrMask & -1314 // Thread is forking. // Stored into g->stackguard0 to cause split stack check failure. // Must be greater than any real sp.stackFork = uintptrMask & -1234
当检查到栈不足够的时候,调用runtime·morestack_noctxt,检查完成之后将重新从函数其实处运行,再进行一次栈check,因为进入newstack有可能并不会增长栈。
0x0000 00000 (x.go:19) MOVQ TLS, CX0x0009 00009 (x.go:19) MOVQ (CX)(TLS*2), CX0x0010 00016 (x.go:19) LEAQ -160(SP), AX0x0018 00024 (x.go:19) CMPQ AX, 16(CX)0x001c 00028 (x.go:19) JLS 637 ...0x027d 00637 (x.go:19) CALL runtime.morestack_noctxt(SB)0x0282 00642 (x.go:19) JMP 0
这个函数调用runtime·morestack
这个函数中:
- 检查是否是从g或者是gsignal中调用的这个函数,如果是,则报错
- 假设调用调用morestack_noctx的函数为f,
- 首先保存f的caller’s SP到m的morebuf 还有PC还有当前g
- 然后保存f的SP PC和BP以及g到当前goroutinue的gobuf
- morebuf主要用于在morestack中出现throw的时候可以正常打印调用栈
- 切换到m.g0的栈上调用runtime.newstack
runtime.newstack
栈扩容安全性检查
if thisg.m.morebuf.g.ptr().stackguard0 == stackFork { throw("stack growth after fork")}
不能再fork之后调用morestack,fork就是栈还没有初始化完的时候,会把栈顶设置为stackFork。
如果morebuf中的g不等于m.curg,报错
gp := thisg.m.curg// Write ctxt to gp.sched. We do this here instead of in// morestack so it has the necessary write barrier.gp.sched.ctxt = ctxtif thisg.m.curg.throwsplit { // Update syscallsp, syscallpc in case traceback uses them. morebuf := thisg.m.morebuf gp.syscallsp = morebuf.sp gp.syscallpc = morebuf.pc print("runtime: newstack sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp) throw("runtime: stack split at bad time")}
不能在throwsplit为ture的时候调用morestack,这个标志表示现在不能进行栈的扩容
判断是否是真的需要扩容
接下来清空m.morebuf
这里判断是不是因为设置了stackPreempt而进去的morestack,如果是,直接把g.stackguard0重新设置为gp.stack.lo + _StackGuard
然后切换到goroutinue继续执行,这里是因为如果一个goroutinue需要被抢占,会设置两个状态 g.stackguard0 = stackPreempt和g.preempt = true
这里当g.stackguard0 == stackpreempt的时候,
如果有锁,内存分配,条件的时候,不进行goroutinue切换
后面如果gp.preemptscan为true,也不进行切换
否则调用gopreempt_m
进行切换
这个函数最终调用schedule和execute来切换到一个新的goroutinue上运行。
扩容
copystack(gp, uintptr(newsize), true)casgstatus(gp, _Gcopystack, _Grunning)gogo(&gp.sched)
调用copystack分配并拷贝栈,然后继续gogo切换到goroutinue继续执行
也就是newstack不但实现了栈的扩容,同时还实现了go的抢占式调度算法
一个小小的疑问及答案不
如果刚好在goroutinue的栈即将不够用的时候设置了stackpreempt,那么是不是有可能因为stackpreempt而没有进行栈扩容而导致栈溢出呢?
关于这个疑问的答案是不会导致栈溢出,请看这里:
0x027d 00637 (x.go:19) CALL runtime.morestack_noctxt(SB) 0x0282 00642 (x.go:19) JMP 0
在runtime.morestack_noctext调用之后会JMP0,也就是如果是因为stackpreempt而进入newstack,那么当goroutinue继续运行之后,会返回函数起始处,重新检查sp和栈顶,这时候栈顶已经被newstack恢复。
栈收缩
收缩栈是在mgcmark.go中触发的,主要是在scanstack和markrootFreeGStacks函数中,也就是垃圾回收的时候会根据情况收缩栈
// Maybe shrink the stack being used by gp.
// Called at garbage collection time.
// gp must be stopped, but the world need not be.
shrinkstack 收缩栈在必要的时候
- 如果这个g是Gdead状态,则会释放栈空间
- 如果已经使用的栈空间大于总栈空间的1/4,则不进行栈收缩,如果是在正在进行系统调用也不能进行栈缩放,因为system使用的参数可能在栈上面。
- 缩小栈的空间为原来的一半
- golang 栈的扩大和收缩
- 【一些数据库的操作(创建,修改,set,收缩,扩大,分离附加等)】
- 一些数据库的操作(创建,修改,set,收缩,扩大,分离附加等
- 【一些数据库的操作(创建,修改,set,收缩,扩大,分离附加等)】
- 对话框的收缩和扩展
- 可以收缩和和伸展的表格
- JQuery的一种特效:展开和收缩
- VC:窗口收缩和扩展的方法
- Jquery实现的文本展开和收缩
- 可展开和收缩的表格
- 对话框部分的收缩和扩展
- jQuery实现图片的展开和收缩
- TextView 的伸展和收缩效果
- ExpandableTextView可以展开和收缩的TextView
- WPF TreeView节点的展开和收缩
- SVM的交叉验证和网格收缩
- ToolBar的滚动展开和收缩
- 封装可展开和收缩的View
- Python基础入门(十四)- List 数组类型
- qt5.7.0配置及apk打包实现
- nio 模拟http服务器
- linux系统,启动、停止、重启crontab服务
- Angularjs上传图片预览--关键代码
- golang 栈的扩大和收缩
- ByteArray to String过程中的编码问题
- 管理javascript的事件基础知识的总结
- C#之ref与out
- Problem D: 字符类的封装
- 通过宏判断VS编译版本以及系统平台
- 新版testFlight中开发人员如何给测试人员推送ios测试包(含使用testFlight要注意的地方)
- angular2学习笔记(3)
- 莫比乌斯反演详解