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

前几天,运维同事给我反馈了一个问题:

通过监控发现,线上的一个服务,业务线程时不时会出现卡顿,卡顿大约持续几秒。

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

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

东北码农,全网同名,欢迎大家使用常用聊天软件关注、评论交流~

如果大家觉得有用,求点赞、转发~

谢谢你~

被vector动态扩容给坑了!的更多相关文章

  1. <实训|第十二天>用LVM对linux分区进行动态扩容

    [root@localhost~]#序言在linux中,我们安装软件的途径一般有那些,你们知道吗?在linux中,如果你的磁盘空间不够用了,你知道如何来扩展磁盘吗?动态扩容不仅在工作中还是在其他方面都 ...

  2. ArrayList和Vector的扩容机制

    ArrayList和Vector都是继承了相同的父类和实现了相同的接口.如下 public class Vector<E> extends AbstractList<E> im ...

  3. Arraylist动态扩容详解

    ArrayList 概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长. ArrayList不是线程安全的,只能用在单线程环境下. 实现了Serializable接口,因此它支 ...

  4. 转:用STL中的vector动态开辟二维数组

    用STL中的vector动态开辟二维数组 源代码:#include <iostream>#include <vector>using namespace std;int mai ...

  5. Redis进阶实践之十二 Redis的Cluster集群动态扩容

    一.引言     上一篇文章我们一步一步的教大家搭建了Redis的Cluster集群环境,形成了3个主节点和3个从节点的Cluster的环境.当然,大家可以使用 Cluster info 命令查看Cl ...

  6. LVM XFS增加硬盘分区容量最后一步的时候动态扩容报错

    在我们lvextend扩容完之后,想动态扩容时出现错误.我们可以用以下命令来进行操作. 若不是xfs我们可以用resize2fs,这里报错了 [root@Mysql01-213-66 ~]# resi ...

  7. 一脸懵逼学习Hdfs---动态增加节点和副本数量管理(Hdfs动态扩容)

    1:按照上篇博客写的,将各个进程都启动起来: 集群规划:    主机名        IP                安装的软件                    运行的进程   master ...

  8. Linux LVM动态扩容

    引用自:  https://blog.csdn.net/u012439646/article/details/73380197   xfs_growfs /dev/centos/root  一.首先安 ...

  9. mysql动态扩容调研

    MySQL动态扩容方案 目前可用方案 MySQL的复制: 一个Master数据库,多个Salve,然后利用MySQL的异步复制能力实现读写分离,这个方案目前应用比较广泛,这种技术对于以读为主的应用很有 ...

随机推荐

  1. Flutter Windows 桌面端支持进入稳定版

    Flutter 创建伊始,我们就致力于打造一个能够构建精美的.可高度定制的.并且可以编译为机器码的跨平台应用解决方案,以充分发挥设备底层硬件的全部图形渲染能力.今天,Flutter 对 Windows ...

  2. Lesson6——Pandas Pandas描述性统计

    1 简介 描述统计学(descriptive statistics)是一门统计学领域的学科,主要研究如何取得反映客观现象的数据,并以图表形式对所搜集的数据进行处理和显示,最终对数据的规律.特征做出综合 ...

  3. 报错:java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp

    感谢原文作者:风起云淡- 原文链接:https://blog.csdn.net/shenguan777/article/details/78615521 异常分析: 在使用MySql时,如果数据库中有 ...

  4. 【Android珍藏】推荐10个炫酷的开源库【转】

    感谢大佬:https://www.jianshu.com/p/d608f0228fd4 前言 技术群里面经常有人问到一些炫酷的UI效果实现方法,有时候我都是给一个相同或者相似效果的Github链接,有 ...

  5. where子句和having子句区别

    感谢大佬:https://blog.csdn.net/XiaopinOo/article/details/78305008 where子句和having子句的区别: 1.where  不能放在grou ...

  6. redhat更改yum源及安装PHP环境

    redhat更新yum源 删除同RHEL一同安装的yum源 rpm -qa|grep yum #查看本地yum yum list | wc -l #看个数 yum install pip #看现象 r ...

  7. 浅谈php web安全

    首先,笔记不是web安全的专家,所以这不是web安全方面专家级文章,而是学习笔记.细心总结文章,里面有些是我们phper不易发现或者说不重视的东西.所以笔者写下来方便以后查阅.在大公司肯定有专门的we ...

  8. jdbc插入或查询数据库时间总是比实际时间少8小时原因

    mysql插入数据库的时间总是有问题,比实际时间要早8小时.检查是jdbc连接的url中配置的时区有问题,原先是 jdbc.url=jdbc:mysql://47.**.**.**:3306/yeey ...

  9. JS字符串去替换元素再转换成数组

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11648074.html JS字符串替换不必要的元素, 然后去除多余的空格, 转换成数组: va ...

  10. Solution -「LOJ #141」回文子串 ||「模板」双向 PAM

    \(\mathcal{Description}\)   Link.   给定字符串 \(s\),处理 \(q\) 次操作: 在 \(s\) 前添加字符串: 在 \(s\) 后添加字符串: 求 \(s\ ...