go对象池化组件bytebufferpool使用详解
本篇文章向大家介绍《go对象池化组件bytebufferpool使用详解》,主要包括gobytebufferpool、对象、池化组件,具有一定的参考价值,需要的朋友可以参考一下。
1. 针对问题
在编程开发的过程中,我们经常会有创建同类对象的场景,这样的操作可能会对性能产生影响,一个比较常见的做法是使用对象池,需要创建对象的时候,我们先从对象池中查找,如果有空闲对象,则从对象池中移除这个对象并将其返回给调用者使用,只有在池中无空闲对象的时候,才会真正创建一个新对象
另一方面,对于使用完的对象,我们并不会对它进行销毁,而是将它放回到对象池以供后续使用,使用对象池在频繁创建和销毁对象的情况下,能大幅的提升性能,同时为了避免对象池中的对象占用过多的内存,对象池一般还配有特定的清理策略,Go的标准库sync.Pool
就是这样一个例子,sync.Pool
中的对象会被垃圾回收清理掉
这类对象中,有一种比较特殊的是字节切片,在做字符串拼接的时候,为了拼接高效,我们通常将中间结果存放在一个字节缓冲中,拼接完之后,再从字节缓冲区生成字符串
Go标准库bytes.Buffer
封装字节切片,提供一些使用接口,我们知道切片的容量是有限的,容量不足时需要进行扩容,而频繁的扩容容易造成性能抖动
bytebufferpool
实现了自己的Buffer
类型,并引入一个简单的算法降低扩容带来的性能损失
2. 使用方法
bytebufferpool
的接入很轻量
func main() { bf := bytebufferpool.Get() bf.WriteString("Hello") bf.WriteString(" World!!") fmt.Println(bf.String()) }
上面的这种用法使用的是defaultPool
,bytebufferpool
的Pool
对象是公开的,也可以自行新建
3. 源码剖析
bytebufferpool
是如何做到最大程度减小内存分配和浪费的呢,先宏观的看整个Pool
的定义,然后细化到相关的方法,就可以找到答案
bytebufferpool
中Pool
结构体的定义为
type Pool struct { calls [steps]uint64 calibrating uint64 defaultSize uint64 maxSize uint64 pool sync.Pool }
其中calls
存储了某一个区间内不同大小对象的个数,calibrating
是一个标志位,标志当前Pool
是否在重新规划中,defaultSize
是元素新建时的默认大小,它的选取逻辑是当前calls
中出现次数最多的对象对应的区间最大值,这样可以防止从对象池中捞取之后的频繁扩容,maxSize
限制了放入Pool
中的最大元素的大小,防止因为一些很大的对象占用过多的内存
bytebufferpool
中定义了一些和defaultSize
及maxSize
计算相关的常量
const ( minBitSize = 6 // 2**6=64 is a CPU cache line size steps = 20 minSize = 1 <p>其中<code>minBitSize</code>表示的是第一个区间对象大小的最大值(2的xx次方-1),在<code>bytebufferpool</code>中,将对象大小分为20个区间,也就是<code>steps</code>,第一个区间为<code>[0, 2^6-1]</code>,第二个为<code>[2^6, 2^7-1]</code>...,依此类推</p> <p><code>calibrateCallsThreshold</code>表示如果某个区间内对象的数量超过这个阈值,则对<code>Pool</code>中的变量进行重新的计算,<code>maxPercentile</code>用于计算<code>Pool</code>中的<code>maxSize</code>,表示前<code>95%</code>的元素大小</p> <p><code>bytebufferpool</code>中的方法也比较少,核心的是<code>Get</code>和<code>Put</code>方法</p>
- Get
func (p *Pool) Get() *ByteBuffer { v := p.pool.Get() if v != nil { return v.(*ByteBuffer) } return &ByteBuffer{ B: make([]byte, 0, atomic.LoadUint64(&p.defaultSize)), } }
可以看到,如果对象池中没有对象的话,会申请defaultSize
大小的切片返回
- Put
func (p *Pool) Put(b *ByteBuffer) { idx := index(len(b.B)) if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold { p.calibrate() } maxSize := int(atomic.LoadUint64(&p.maxSize)) if maxSize == 0 || cap(b.B) <p>Put方法会比较麻烦,我们分步来看</p>
- 计算放入元素在
calls
数组中的位置
func index(n int) int { n-- n >>= minBitSize idx := 0 for n > 0 { n >>= 1 idx++ } if idx >= steps { idx = steps - 1 } return idx }
这里的逻辑就是先将长度右移minBitSize
,如果依然大于0,则每次右移一位,idx加1,最后如果idx超出了总的steps
(20),则位置就在最后一个区间
- 判断当前区间放入元素的个数是否超过了
calibrateCallsThreshold
指定的阈值,超过则重新计算Pool
中元素的值
func (p *Pool) calibrate() { // 如果正在重新计算,则返回,控制多并发 if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) { return } // 计算每一段区间中的元素个数 & 元素总个数 a := make(callSizes, 0, steps) var callsSum uint64 for i := uint64(0); i maxSum { break } callsSum += a[i].calls size := a[i].size if size > maxSize { maxSize = size } } // 对defaultSize和maxSize进行赋值 atomic.StoreUint64(&p.defaultSize, defaultSize) atomic.StoreUint64(&p.maxSize, maxSize) atomic.StoreUint64(&p.calibrating, 0) }
- 判断当前放入元素的大小是否超过了
maxSize
,超过则不放入对象池中
今天关于《go对象池化组件bytebufferpool使用详解》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

- 上一篇
- Golang交叉编译之跨平台编译使用详解

- 下一篇
- Go项目实现优雅关机与平滑重启功能
-
- 结实的水蜜桃
- 这篇技术文章真是及时雨啊,大佬加油!
- 2023-05-05 13:25:26
-
- 优美的果汁
- 写的不错,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢师傅分享博文!
- 2023-03-10 21:50:29
-
- 认真的蚂蚁
- 太全面了,收藏了,感谢作者的这篇技术文章,我会继续支持!
- 2023-02-28 19:07:23
-
- 高高的蜡烛
- 这篇技术文章真是及时雨啊,细节满满,写的不错,已加入收藏夹了,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-01-11 18:21:52
-
- Golang · Go教程 | 2分钟前 |
- GolangHTTP限流与并发控制方法
- 470浏览 收藏
-
- Golang · Go教程 | 5分钟前 |
- Golang配置文件与环境变量结合方法
- 311浏览 收藏
-
- Golang · Go教程 | 7分钟前 |
- Golang事件溯源实现方法解析
- 338浏览 收藏
-
- Golang · Go教程 | 32分钟前 |
- Golang字符串解析:Parse函数全攻略
- 411浏览 收藏
-
- Golang · Go教程 | 42分钟前 |
- Go语言跨平台编译技巧1.5版本全解析
- 114浏览 收藏
-
- Golang · Go教程 | 46分钟前 |
- Golang基准测试对比,benchcmp分析性能变化
- 203浏览 收藏
-
- Golang · Go教程 | 48分钟前 |
- Golang微服务扩容缩容技巧分享
- 172浏览 收藏
-
- Golang · Go教程 | 51分钟前 |
- Golangchannel实现惰性迭代优化
- 138浏览 收藏
-
- Golang · Go教程 | 56分钟前 |
- Golang微服务设计与模式解析指南
- 298浏览 收藏
-
- Golang · Go教程 | 1小时前 | golang 错误处理 json.SyntaxError json.RawMessage JSON编解码
- GolangJSON编解码错误类型有哪些
- 403浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 514次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- AI Mermaid流程图
- SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
- 560次使用
-
- 搜获客【笔记生成器】
- 搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
- 563次使用
-
- iTerms
- iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
- 583次使用
-
- TokenPony
- TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
- 648次使用
-
- 迅捷AIPPT
- 迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
- 547次使用
-
- go语言中的面向对象
- 2022-12-29 336浏览
-
- golang 对象深拷贝的常见方式及性能
- 2022-12-28 262浏览
-
- 如何go语言比较两个对象是否深度相同
- 2023-01-07 236浏览
-
- golang中接口对象的转型两种方式
- 2023-02-24 247浏览
-
- golang 如何通过反射创建新对象
- 2022-12-23 358浏览