被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
东北码农,全网同名,欢迎大家使用常用聊天软件关注、评论交流~
如果大家觉得有用,求点赞、转发~
谢谢你~
被vector动态扩容给坑了!的更多相关文章
- <实训|第十二天>用LVM对linux分区进行动态扩容
[root@localhost~]#序言在linux中,我们安装软件的途径一般有那些,你们知道吗?在linux中,如果你的磁盘空间不够用了,你知道如何来扩展磁盘吗?动态扩容不仅在工作中还是在其他方面都 ...
- ArrayList和Vector的扩容机制
ArrayList和Vector都是继承了相同的父类和实现了相同的接口.如下 public class Vector<E> extends AbstractList<E> im ...
- Arraylist动态扩容详解
ArrayList 概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长. ArrayList不是线程安全的,只能用在单线程环境下. 实现了Serializable接口,因此它支 ...
- 转:用STL中的vector动态开辟二维数组
用STL中的vector动态开辟二维数组 源代码:#include <iostream>#include <vector>using namespace std;int mai ...
- Redis进阶实践之十二 Redis的Cluster集群动态扩容
一.引言 上一篇文章我们一步一步的教大家搭建了Redis的Cluster集群环境,形成了3个主节点和3个从节点的Cluster的环境.当然,大家可以使用 Cluster info 命令查看Cl ...
- LVM XFS增加硬盘分区容量最后一步的时候动态扩容报错
在我们lvextend扩容完之后,想动态扩容时出现错误.我们可以用以下命令来进行操作. 若不是xfs我们可以用resize2fs,这里报错了 [root@Mysql01-213-66 ~]# resi ...
- 一脸懵逼学习Hdfs---动态增加节点和副本数量管理(Hdfs动态扩容)
1:按照上篇博客写的,将各个进程都启动起来: 集群规划: 主机名 IP 安装的软件 运行的进程 master ...
- Linux LVM动态扩容
引用自: https://blog.csdn.net/u012439646/article/details/73380197 xfs_growfs /dev/centos/root 一.首先安 ...
- mysql动态扩容调研
MySQL动态扩容方案 目前可用方案 MySQL的复制: 一个Master数据库,多个Salve,然后利用MySQL的异步复制能力实现读写分离,这个方案目前应用比较广泛,这种技术对于以读为主的应用很有 ...
随机推荐
- ApacheCN PythonWeb 译文集 20211028 更新
Django By Example 中文版 1 创建一个博客应用 2 为博客添加高级功能 3 扩展你的博客应用 4 创建一个社交网站 5 分享内容到你的网站 6 跟踪用户动作 7 构建在线商店 8 管 ...
- Linux中3个文件查找相关命令详解
源于:https://mp.weixin.qq.com/s/VPs-IXY6RoxbltHIxtIbng which命令 我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令 ...
- Tomcat多实例单应用部署方案 (转)
一.Tomcat部署的场景分析 通常,我们对tomcat部署需求可以分为几种:单实例单应用,单实例多应用,多实例单应用,多实例多应用. 对于第一种场景,如果不要求周期性地维护tomcat版本,一般的做 ...
- 运行时异常&编译时异常
/* 异常体系: --------| Throwable 所有错误或者异常的父类 --------------| Error(错误) --------------| Exception(异常) 异常一 ...
- Mac 屏幕录制Gif 制作 By-胡罗
一.视频录制 1)使用Mac系统自带的QuickTime进行屏幕录像 手动打开(如下图) 详细 Mac 基础教程:如何使用 Mac 系统原生的屏幕录制功能 相关快捷键 option+command+n ...
- Kubernetes二进制(单/多节点)部署
Kubernetes二进制(单/多节点)部署 目录 Kubernetes二进制(单/多节点)部署 一.常见的K8S部署方式 1. Minikube 2. Kubeadmin 3. 二进制安装部署 4. ...
- Elementui【tooltip】 在弹框关闭之后再次‘出现’的问题
如图,第一次弹窗进来的时候,符合条件之后,这个提示文字的位置是对的,而且正常显示: 现在点击取消按钮,第二次进入弹窗,如图,提示文字就跑到了左上角,而且输入符合条件的数值之后,会另外显示一个toolt ...
- Docker创建私有镜像仓库
Docker官方提供了一个工具docker-registry,可以借助这个工具构建私有镜像仓库: 1.拉取registry镜像 # docker pull registry//可以使用 docker ...
- MySQL高性能学习笔记
索引 何为索引?有什么作用? 索引是一种用于快速查询和检索数据的数据结构.常见的索引结构有: B 树, B+树和 Hash. 索引的作用就相当于目录的作用.打个比方: 我们在查字典的时候,如果没有目录 ...
- suse 12 安装git客户端
suse-linux:~ # zypper addrepo http://download.opensuse.org/repositories/devel:/tools:/scm/SLE_12_SP5 ...