Golang对象复用静态代码检查工具

BeckJiang · · 797 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一、对象复用

在高并发的场景下使用golang,优化GC都会无法回避的问题。搜索「golang 垃圾回收优化」出来的结果基本上都会提及对象复用的方式,在实践中也确实很多高性能的开源库大量使用对象复用来优化程序,比如fasthttp。

简单的例子

使用对象复用分为三个环节,1.初始化pool;2.获取对象;3.清空对象+归还对象。

package main
import (
    "fmt"
    "sync"
)

var pool *sync.Pool

type Person struct {
    Name string
}

func (p *Person)Reset() {
  p.Name = ""
}

func initPool() {
    pool = &sync.Pool {
        New: func()interface{} {
            fmt.Println("Creating a new Person")
            return new(Person)
        },
    }
}

func main() {
    // 1. 初始化池
    initPool()
    // 2. 获取对象
    p := pool.Get().(*Person)

    p.Name = "first"

    // 3. 清空对象 + 归还对象
    p.Reset()
    pool.Put(p)

}

二、对象复用的坑

在上面的例子中,如果我们把Reset函数注释了,那么放回池子里的Person对象的Name是不干净的,很有可能会影响下一个使用的地方。不过实际使用中忘记调用Reset方法的比较少,这是对象复用的基本意识,真正容易遗漏的是Reset方法中的实现。

在项目实践中,某些结构体定义的字段会比较多,而项目又一直在迭代,结构体的字段会发生新增、修改或删除,如果新增了字段,但Reset方法漏了新增对应的Reset语句,那么程序就很可能会出现数据篡乱的问题,而且这种问题不是稳定必现的,如果未意识到是字段漏了重置的问题,定位起来让人很头疼。

三、工具比人靠谱

想要避免出现这种问题,完全依赖个人注意肯定是不靠谱的,一个项目可能有多个人维护,团队也可能会有新人,难以确保每个人都能顾及到所有的对象复用。于是我开发了一个静态代码检查的工具 structreset用于检查对象复用的结构体的Reset方法,是否包含所有结构体字段的重置。当然这里的方法名Reset是我这里定义的,也可以叫别的名字:free/release等等。

代码仓库里的实现是:识别带有refcount字段的结构体,然后遍历其Reset方法体语句。这个可以根据项目需求进行修改。

var refCountTypeName = map[string]uint8 {"refcount": 1}

安装

按照文档操作即可。

git clone git@git.kgidc.cn:beckjiang/structreset.git

cd structreset

./install.sh

使用

检查项目testdata

structresetx -d ./analysis/passes/structreset/testdata
image.png

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:BeckJiang

查看原文:Golang对象复用静态代码检查工具

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

797 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传