map使用不当导致cpu暴涨

上线新功能导致服务器cpu暴涨。经分析为map assign过于频繁,导致频繁的内存malloc与memorymove,耗尽cpu。

使用go tool定位过程记录

1. 获取进程内函数执行统计

    go tool pprof http://10.139.252.109:9360/debug/pprof/profile
    top10的函数如下:    

2. runtime.mapassign占了40.25%的cpu时间,初步判断是map使用不当导致。

    使用web命令获取可视化执行路径

     

3. 下载到windows本地,用chrome打开,如下

     

注意中间最粗的条线。耗时75.77s(统计总共收集了102秒的运行记录),占了70%多的cpu执行时间。一直往下看可以看到主要耗在这两个函数上。而且这两个函数会导致大量的垃圾回收(因为有大量的map指针)

这两个函数有大量的runtime.mapassign。可见问题肯定在map的使用不当上。

4. 分析代码

    原来的代码如下:
     

发现两个问题
a:) for循环里每次map分配都会申请新的内存,而且会带来频繁的扩容(导致大量内存move)。

b:) map[string]map[int]int 这个数据结构的定义有问题。经过分析上下文,发现map[int]int这个数据结构的用处只是存两个值而已。所以没必要用map[int]int

5. 解决方法

a:) 因为map是指针类型,所以垃圾回收会扫描(垃圾回收只会扫描指针类型数据)。根据上面的分析,map[int]int可以换成struct{a int, b int}。 struct是值类型,所以就避免了大量的垃圾回收对cpu的消耗,同时减少了堆内存的分配。

    修改后的数据结构为:

        struct Unit{t int, d int}

        map[string]Unit

b:) 针对第一个问题:

    因为代码中map的大小是可以提前算出来的,所以提前分配大小。
    第一行代码改为
    clkFromatFqMap := make(map[string]Unit, len(fqMap))

    问题解决,cpu恢复正常。

posted @ 2016-10-11 16:36  黑暗遊侠  阅读(1542)  评论(0编辑  收藏  举报