针对大型复杂map的GC优化, 变成map[uint64]int+外部二级索引切片 大幅减少GC耗时

yudeguang · 2022-07-18 10:58:01 · 3163 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2022-07-18 10:58:01 的主题,其中的信息可能已经有所发展或是发生改变。

noGCMapIndex

对于大型map,比如总数达到千万级别的map,如果键或者值中包含引用类型(string类型,结构体类型,或者任何基本类型+指针的定义 int, float 等),那么这个MAP在垃圾回收的时候就会非常慢,GC的周期回收时间可以达到秒级。

所以对于这种map需要进行优化,把复杂的不利于GC的复杂map转化为基础类型的 map[uint64]int+外部二级索引切片的形式。比如 map[string]intercace{} 转换为 map[uint64]int+[]intercace{}的形式,变成这种形式之后,整个gc基本就不耗时了。

注意,这种做法主要适用于单次加载完后,键值对不再变化的情况。对于键值对在运行过程中还要动态增减的情况则不适合。

package main

import (
    "github.com/yudeguang/noGCMapIndex"
    "log"
    "strconv"
)

func main() {
    log.SetFlags(log.Lshortfile | log.Ltime)
    tstring()
    tint()
}

func tstring() {
    //旧MAP
    type col struct {
        a string
        b string
        c int
    }
    oldMap := make(map[string]col)
    for i := 0; i < 10; i++ {
        oldMap[strconv.Itoa(i)] = col{strconv.Itoa(i), strconv.Itoa(i), i}
    }

    //旧MAP转换为新形式的map+二级索引切片的形式
    data := make([]col, len(oldMap))
    m := noGCMapIndex.NewString(len(oldMap))
    for k, v := range oldMap {
        index := m.CreateIndex(k)
        data[index] = v
    }
    //查询数据
    key := "3"
    index := m.GetIndex(key)
    if index != -1 {
        log.Println("key:", key, "对应的值为:", data[index])
    } else {
        log.Println(key, "不存在")
    }
}

func tint() {
    //旧MAP
    type col struct {
        a string
        b string
        c int
    }
    oldMap := make(map[int]col)
    for i := 0; i < 10; i++ {
        oldMap[i] = col{strconv.Itoa(i), strconv.Itoa(i), i}
    }

    //旧MAP转换为新形式的map+二级索引切片的形式
    data := make([]col, len(oldMap))
    m := noGCMapIndex.NewInt(len(oldMap))
    for k, v := range oldMap {
        index := m.CreateIndex(k)
        data[index] = v
    }
    //查询数据
    key := 3
    index := m.GetIndex(key)
    if index != -1 {
        log.Println("key:", key, "对应的值为:", data[index])
    } else {
        log.Println(key, "不存在")
    }
}

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

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

3163 次点击  
加入收藏 微博
4 回复  |  直到 2022-07-20 11:31:32
Mericusta
Mericusta · #1 · 3年之前

键值对不再变化,还存在 GC 的需求吗?

yudeguang
yudeguang · #2 · 3年之前
MericustaMericusta #1 回复

键值对不再变化,还存在 GC 的需求吗?

会的,只要不是基础类型的map,在GC的时候都会被逐一扫描。高版本的GO对基础类型的MAP做了优化,不会被扫描

liangmanlin
liangmanlin · #3 · 3年之前

千万级别这种设计也是有问题的,大概率申请slice的内存就会失败

LYL_GO
LYL_GO · #4 · 3年之前

适用场景太局限,如果能做到对动态MAP做GC优化那就更好了

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