Go Ballast(通过尝试降低 GC 频率以提高整体性能,针对所有 Go应用都适用)
首先我们明白GO语言GC触发条件是由比例来触发的。例如,当前存活内存10GB,触发比例是100%,因此下次触发GC的时候是当内存达到20GB的时候触发GC。这种机制在当前小内存的情况下会平凡触发GC,例如当前只有1GC的话则内存达到2GB就要触发GC。而单纯提高比例到1000%,那么下次触发GC的时候实际上内存已经有较大的压力。所以,我们采用Ballast机制。
Ballast机制在小内存的时候会申请一些内存,已达到延缓下一次GC的时间。具体的,也就一行代码:
// allocate 2GB ballast which resident in virtual memory only
ballastObject := make([]byte,1024*1024*1024*2)
首先,内存是在续存中分配,所以实际上我们是申请了这块内存但没映射到物理内存。
假设除 Ballast 以外的存活对象总大小为X字节(平均值),Ballast 对象大小为 B字节
1.Ballat 最多会带来大约 B 字节的额外物理内存使用(值得注意的是,这部分多占用的物理内存依然是被除 Ballast 以外的对象所使用,不存在浪费问题,Ballast 本身仅仅存在于虚拟内存中,不会被实际地映射物理页面)
2 Ballast能带来性能优化的根本原因是降低了GC频率
根据1得到:不管大内存还是小内存场景,Ballast 都会额外带来最大为 B 字节的物理内存使用。
根据2得到:在大内存场景即X比较大时,一般来说此时 GC频率会比较小,所以 Ballast带来的优化效果不会像 X 为较小值时那么明显。
那么这样做在清理内存是否会占用更多时间?
答案:不会。GC主要是mark 和sweep。其中sweep速度很快,几乎不暂用时间。在mark阶段由于Ballast不是存活对像,所以不会被扫描到,因此几乎也不占用时间。
CPUWorker(尝试给 Go 带来一个类似内核 CFS 调度器的 goroutime 调度器,以通过其提供的优先级机制保证关键goroutine 的延迟指标,目前还没有在TiDB中尝试 应用,Demo效果很好).
在linux中的调度算法采用CFS算法。CFS算法在休眠进程在唤醒时会获得vruntime的补偿(减少vruntime,提高这个进程优先级),它在醒来的时候有能力抢占CPU是大概率事件,这也是CFS调度算法的本意,即保证交互式进程的响应速度,因为交互式进程等待用户输入会频繁休眠。
- 计算密集型作业将运行很长时间,因此它将优先级放后;
- I/O密集型作业会运行很短的时间,因此它只会稍微放后移动;
而goruntime调度器采用的是RR方式。这对IO密集型作业很不友好,交互式进程交互能力差。
解决方式:
1,使用CGO。但是CGO执行write的时候将会导致大内存复制。
2,再来一个并行的GOruntime实例进程。将go library编译成CGO.so文件,然后通过我们GO的CGO来调用这个.so文件。所以这时候其实是有两个隔开的进程也就是两个GMP模型,所以原来的程序和这个IO密集型的.so文件的程序是不会互相影响的。
3,使用CPU worker。文章来源:https://www.toymoban.com/news/detail-653076.html
https://docs.google.com/document/d/1g5SgpMg28XyMFdPTVMrZrZiLFBfAIgW8sMEXkKEQTzE/edit文章来源地址https://www.toymoban.com/news/detail-653076.html
到了这里,关于GO语言自底向上优化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!