C++——vector:resize与reserve的区别,验证写入4GB大数据时相比原生操作的效率提升

resize和reserve的区别

reserve:预留空间,但不实例化元素对象。所以在没有添加新的对象之前,不能引用容器内的元素。而要通过调用push_back或者insert。

resize:改变容器元素的数量,且会实例化对象(指定或默认0)。因此,调用resize之后,可以直接引用容器内的对象。此时再调用push_back,是加在这个新的空间后面,即size之后的。同样也会触发push_back()的空间预留机制。

如果newSize < size,则该容器后部的元素会被析构,且resize可能会使迭代器失效,对于所有的容器类型,如果resize操作压缩了容器,则指向已删除的元素的迭代器失效。同样的,扩容也可能导致迭代器失效,因为原来迭代器指向的位置的内存已经被释放,因为内存被移动到了别的位置。比如如果count大于size,则会扩容,如果后续空间不够,需要寻找一块足够的空间,然后把元素逐个复制过去。

当元素写入不超过预留空间时,reserve()不涉及内存的重新分配,resize()会涉及内存的重新分配。

reserve()只修改capacity大小,不修改size大小,resize()既修改capacity大小,也修改size大小。

如果reserve和resize的newSize大于capacity,都会涉及内存分配。

申请和写入大内存时三者的差异

以下的代码示例是在Linux平台下运行的。

cpp 复制代码
void test_reserve()
{
    clock_t start = clock();
    std::vector<int> arr1;
    arr1.reserve(1000000000);

    /* 10^9 * 4 / 1024 / 1024 = 3814MB */
    for(int i = 0; i < 1000000000; i++)
    {
        arr1.push_back(i);
    }
    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    std::cout <<"size:"<< arr1.size() << " capacity:" << arr1.capacity() << std::endl;
    /*
        耗时:13.52 秒
        size:1000000000 capacity:1000000000
    */
}

void test_resize()
{
    clock_t start = clock();
    std::vector<int> arr1;
    arr1.resize(1000000000);

    /* 10^9 * 4 / 1024 / 1024 = 3814MB */
    for(int i = 0; i < 1000000000; i++)
    {
        arr1[i] = i;
    }

    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    std::cout <<"size:"<< arr1.size() << " capacity:" << arr1.capacity() << std::endl;
    /*
        耗时:6.39秒
        size:1000000000 capacity:1000000000
    */
}

class test
{
    public:
    test() {std::cout << "构造" << std::endl; }
    ~test() {std::cout << "析构" << std::endl; }
};

int main()
{
    clock_t start = clock();
    std::vector<int> arr;

    /* 10^9 * 4 / 1024 / 1024 = 3814MB */
    for(int i = 0; i < 1000000000; i++)
    {
        arr.push_back(i);
    }
    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    std::cout <<"size:"<< arr.size() << " capacity:" << arr.capacity() << std::endl;
    /*
        耗时:18.68 秒
        size:1000000000 capacity:1073741824
    */

    test_reserve();
    test_resize();
    return 0;
}

可以看到,reserve相比原生操作快了5秒,而resize后直接通过下标写入,比原生快了12秒,提升还是很可观的。但是前提是要知道元素的个数。

在进程运行的过程中,可以通过shell脚本实时查看进程的内存占用。

这个脚本的意思是:死循环,提取ps aux指令的第一行,即各种参数的标题,并且再提取a.out即程序名的各项信息,之后打印换行,睡眠1秒。达到每隔一秒监控一次内存占用的效果。

powershell 复制代码
while true; 
do ps aux | head -1 ; ps aux | grep a.out; 
printf "------------------------------------------------------------------------------------------------------------------------------------\n\n" ; sleep 1; 
done

上图是使用reserve的情况,可以看到VSZ即虚拟内存在调用reserve之后就飙到了4GB,因为Linux是内存延时分配的,即使用了该内存空间才实际分配物理内存。又因为vector的扩容方式是1.5倍扩容,因此可以看到,在push_back的过程中RSS即实际物理内存是逐渐上升的。

而上图是使用resize的情况,因为resize是实际分配了空间并会实例化元素的,因此物理内存占用上升的非常快,几乎几秒就占满了4GB。

相关推荐
小林想被监督学习17 分钟前
RabbitMQ 仲裁队列 -- 解决 RabbitMQ 集群数据不同步的问题
linux·分布式·rabbitmq
Icomi_43 分钟前
【外文原版书阅读】《机器学习前置知识》1.线性代数的重要性,初识向量以及向量加法
c语言·c++·人工智能·深度学习·神经网络·机器学习·计算机视觉
apocelipes44 分钟前
Linux glibc自带哈希表的用例及性能测试
c语言·c++·哈希表·linux编程
xf8079891 小时前
cursor远程调试Ubuntu以及打开Ubuntu里面的项目
linux·运维·ubuntu
dot to one1 小时前
Linux 入门 常用指令 详细版
linux·服务器·centos
sysu631 小时前
95.不同的二叉搜索树Ⅱ python
开发语言·数据结构·python·算法·leetcode·面试·深度优先
Ronin-Lotus1 小时前
上位机知识篇---CMake
c语言·c++·笔记·学习·跨平台·编译·cmake
lxl13072 小时前
学习数据结构(2)空间复杂度+顺序表
数据结构·学习
Golinie2 小时前
记一次Linux共享内存段排除Bug:key值为0x0000000的共享内存段删除不了
linux·bug·共享内存段
狄加山6752 小时前
Linux 基础1
linux·运维·服务器