使用CGO进行GC优化的注意事项

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

前阵子我利用cgo对游戏内存数据库的数据存储方式做了优化,减少了对象数量。但是程序放到线上环境后出现了段错误,直接导致进程退出,只好临时又把优化的部分去掉,去掉后程序又继续稳定运行了两周。

优化代码撤下来后,我重新整理了代码。整理下来,我觉得对含有字符串字段的表的优化逻辑太过复杂了,并且很难控制边界情况。

这里举个例子:

type MyTable struct {
    Name string
}

func InsertMyTable(myTable MyTable) {
    nameLen := C.size_t(len(myTable.Name))
    name := C.calloc(1, nameLen)
    C.memcpy(name, unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&myTable.Name)).Data), nameLen)
    (*reflect.StringHeader)(unsafe.Pointer(&myTable.Name)).Data = uintptr(name)
}

func UpdateMyTable(myTable MyTable) {
    nameLen := C.size_t(len(myTable.Name))
    name := C.calloc(1, nameLen)
    C.memcpy(name, unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&myTable.Name)).Data), nameLen)
    (*reflect.StringHeader)(unsafe.Pointer(&myTable.Name)).Data = uintptr(name)

    C.free(unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&oldMyTable.Name)).Data))
}

func DeleteMyTable(myTable MyTable) {
    C.free(unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&myTable.Name)).Data))
}

上面的代码是对项目中遇到的问题的模拟,不是真实代码,真实代码其实比这个要复杂,因为对象会被用于事务提交,还需要控制对象在事务提交后才能释放字符串类型字段,在更新时还需要判断字符串是否有变更等等。

为什么需要对字符串进行处理呢?因为如果不对字符串进行处理的话,当go的字符串被赋值给cgo创建的内存块后,go并不不清楚字符串被引用,从而导致有用的字符串被gc回收。

同样的道理也适用于嵌套的结构,例如:

type MyTable struct {
    ChildTable *MyChildTable
}

如果一个go创建的MyChildTable对象被赋值给一个cgo维护的MyTable对象的ChildTable字段,go的gc是跟踪不到这个引用关系的,这时候会出现MyTable对象还有效的时候,内部的ChildTable字段所引用的go对象已经被回收,如果程序访问ChildTable对象,就会出现段错误。

但是子表的情况是比较好处理的,只要原来new(MyChildTable)的地方替换为自己实现的newMyChildTable(),用cgo来申请内存,自己手工释放,就不会有问题,边界情况也没有字符串那么多。代码像这样:

sizeofMyChildTable := unsafe.SizeOf(MyChildTable{})

func newMyChildTable() *MyChildTable {
    return (*MyChildTable)(C.calloc(1, C.size_t(sizeofMyChildTable)))
}

排查段错误很困难,所以我想先做排除法,首先去掉了最复杂的字符串优化逻辑,含有字符串类型字段的内存表都不进行优化。还好游戏中字符串用得不多,只有少数几个表有用到字符串,稍微降低优化效果提高程序稳定性,还是划算的。

去掉字符串优化后的新版程序,已经稳定允许了一周,算是正式验证了cgo进行GC优化的有效性。


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

本文来自:达达的主页

感谢作者:达达

查看原文:使用CGO进行GC优化的注意事项

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

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