被vector动态扩容给坑了!

大家好,我是东北码农。记录一下工作中事。

前几天,运维同事给我反馈了一个问题:
通过监控发现,线上的一个服务,业务线程时不时会出现卡顿,卡顿大约持续几秒。

我们做金融系统后台开发的,对性能要求很严格的,当然要查一查啦。

1、问题调查

1.1、top 日志

top中有内存和cpu信息,可以判断出卡顿时内存使用暴涨,但cpu使用没有下降。
应该是做了非常耗cpu和内存的操作,而不是等待什么。

1.2、代码分析

通过top的分析,结合代码分析,发现业务代码中有vector操作,每收到一个包都会建立索引。伪代码如下

vector<uint64_t> idx_;

void on_recv(pkg *h)
{
    idx_.push_back(h->seq);
}

应该是vector动态扩容时,造成的卡顿。下面来验证一下。

2、vector

std::vector is a sequence container that encapsulates dynamic size arrays.

vector的底层实现是数组,在使用时采取动态扩容方式。

2.1、vector的size和capacity

vector有size和capacity两个属性,size是实际数量,capacity是容器当前容量。下面是cppreference中的解释:

  • size:returns the number of elements。
  • capacity:returns the number of elements that can be held in currently allocated storage。

2.2、扩容

下面写代码,观察一下vector何时会扩容,以及扩容时的开销。伪代码如下:在扩容时打印容量变化,以及耗时。

void test_vector()
{
    vector<uint64_t> idxs;
    uint64_t last_cap = 0;
    for(int i = 0 ;i < 1200000000;i++)
    {
        auto begin = get_ns();
        idxs.push_back(i);
        auto cost = get_ns() - begin;

        auto cap = idxs.capacity();
        if(last_cap != cap || cost > 100*1000*1000)
        {
            printf("last_cap=%ju,cap=%ju,cost=%ju\n",last_cap,cap,cost/1000000);
            last_cap = cap;
        }
    }
}

输出如下:

last_cap=0,cap=1,cost=0
last_cap=1,cap=2,cost=0
last_cap=2,cap=4,cost=0
last_cap=4,cap=8,cost=0
last_cap=8,cap=16,cost=0
last_cap=16,cap=32,cost=0
last_cap=32,cap=64,cost=0
last_cap=64,cap=128,cost=0
last_cap=128,cap=256,cost=0
last_cap=256,cap=512,cost=0
last_cap=512,cap=1024,cost=0
last_cap=1024,cap=2048,cost=0
last_cap=2048,cap=4096,cost=0
last_cap=4096,cap=8192,cost=0
last_cap=8192,cap=16384,cost=0
last_cap=16384,cap=32768,cost=0
last_cap=32768,cap=65536,cost=0
last_cap=65536,cap=131072,cost=0
last_cap=131072,cap=262144,cost=0
last_cap=262144,cap=524288,cost=1
last_cap=524288,cap=1048576,cost=1
last_cap=1048576,cap=2097152,cost=3
last_cap=2097152,cap=4194304,cost=6
last_cap=4194304,cap=8388608,cost=13
last_cap=8388608,cap=16777216,cost=25
last_cap=16777216,cap=33554432,cost=51
last_cap=33554432,cap=67108864,cost=102
last_cap=67108864,cap=134217728,cost=204
last_cap=134217728,cap=268435456,cost=407
last_cap=268435456,cap=536870912,cost=818
last_cap=536870912,cap=1073741824,cost=1633
last_cap=1073741824,cap=2147483648,cost=3372

可以看出,vector在2的n次幂都会扩容。重要节点是

  • capacity :1.3亿~2.6亿-时间约400ms
  • capacity :2.6亿~5.3亿-时间约800ms
  • capacity :5.3亿~10.7亿-时间约1600ms

3、问题解决

问题找到了,解决就容易了。
vector有reserve接口,可以在程序启动时就扩容好,防止运行时动态扩容造成卡顿。
其实程序在启动时,已经调用reserve提前扩容了,但是近期国际局势不稳定,造成订单量飙升,所以reserve的量不足,需要重新估计一下。

  • reserve:reserves storage

东北码农,全网同名,欢迎大家使用常用聊天软件关注、评论交流~
如果大家觉得有用,求点赞、转发~
谢谢你~

posted @ 2022-03-12 22:54  东北码农  阅读(505)  评论(1编辑  收藏  举报