vector | reserve和resize方法的区别 以及 增容机制

一.reverse和resize方法的区别

函数原型:

void reserve(size_t n); //扩增容器的容量
void resize(size_t n); //改变容器内的有效元素个数

reserve:

  • 如果n大于容器现有的容量(即capacity()),则需要在自由内存区为整个容器重新分配一块新的更大的连续空间,其大小为n*sizeof(T).然后将容器内所有有效元素从旧位置全部复制到新位置(调用拷贝构造函数),最后释放旧位置的所有存储空间并调整容器对象的元素位置指示器.(vector:将那3个指针指向新内存区的相对位置)
  • 否则,什么都不用做

resize:

  • 如果n大于容器当前的大小(即size()),则在容器的末尾插入n=size()个初值为C的元素,如果不指定初值,则用元素类型的默认构造函数来初始化每一个新元素(很可能引起内存重新分配以及容器的扩张)
  • 如果n小于容器当前的大小(即size()),则从容器的末尾删除size()-n个元素,但是不释放元素本身的内存空间,因此容量不变.

二.vector的扩容机制

(1).扩容机制

当向vector中插入元素时,如果元素有效个数size与空间容量capacity相等时,vector内部会触发扩容机制:

  1. 开辟新空间
  2. 拷贝元素
  3. 释放原有空间(旧空间)

注意:每次扩容新空间不能太大,也不能太小.太大容易造成空间浪费,太小则会导致频繁扩容而影响程序效率.

(2).如何避免扩容导致效率低

如果在插入之前可以预估vector将要存储的元素个数,提前将底层容量开辟好即可.如果插入之前进行reserve,只要空间给足,则插入时不会扩容.如果没有reserve,则会边插入边扩容,效率会极其低下.

(3).capacity增长问题

在Windows的vs环境下,capacity的增长接近于1.5倍,而在Linux的g++环境下,capacity的增长是2倍.

两者之间的分歧主要是体现在: 优先考虑时间还是空间的问题.

对于g++2倍增容:

优点: 每次申请的空间足够多时,就能减少扩容的次数.每次扩容都要申请空间,拷贝数据,销毁原空间,所以这样能够大大的提升效率

缺点: 有可能因为申请的空间过多造成资源的浪费

因此这是典型的以空间换时间的做法.

对于vs1.5倍增容:
优点: 每次申请1.5倍的空间,这样就可以更好的利用空间,比起2倍更不容易造成资源浪费

缺点: 如果需求的空间过大,就需要多次扩容,因为扩容的次数过多,导致效率低

因此这是典型的以时间换空间的作法.

(4).为什么选择1.5倍或者2倍的方式扩容,而不是3倍4倍呢?

扩容原理: 申请新空间,拷贝元素,释放旧空间,理想的分配方案是在第N次扩容时如果能复用之前N-1次释放的空间就太好了

如果按照2倍的方式扩容,第i次扩容空间大小为:

1 2 4 8 16 32 ......2^i

可以看到,每次扩容时,前面释放的空间都不能再次使用.

比如:第4次扩容时,前2次空间已经被释放,第3次空间还没有被释放(开辟空间,拷贝元素,释放旧元素),即前面释放的空间只有1+2 = 3,假设第3次的空间已经释放才只有1+2+4 = 7,而第四次需要8个空间,因此无法使用之前已经释放的空间,但是按照小于2倍的方式扩容,多次扩容之后就可以复用之前释放的空间.

如果倍数超过2倍(包含2倍)方式扩容会存在:

  1. 空间浪费可能会比较高(比如:扩容后,申请了64个空间,但只存了33个元素,有接近一半的空间没有使用

  2. 无法使用到前面已经释放的内存

(5).Windows和Linux的扩容底层原理

Windows:

Windows中堆管理系统会对释放的堆块进行合并,因此:vs下的vector扩容机制选择使用1.5倍的方式扩容,这样多次扩容之后,就可以使用之前已经释放的空间.

linux:

linux下主要使用glibc的ptmalloc来进行用户空间申请的.如果malloc的空间小于128KB,其内部通过brk()来扩张,如果大于128KB且arena中没有足够的空间时,通过mmap将内存映射到进程地址空间.

linux中引入伙伴系统为内核提供了一种用于分配一下连续的页而建立的一种高效的分配策略,对固定分区和动态分区方式的折中,固定分区存在内部碎片,动态分区存在外部碎片,而且动态分区回收时的合并以及分配时的切片是比较耗时的.

伙伴系统是将整个内存区域构建成基本大小basicSize的1倍、2倍、4倍、8倍、16倍等,即要求内存空间分区链均对应2的整次幂倍大小的空间,整齐划一,有规律的而不是乱糟糟的。

在分配和释放空间时,可以通过log2(request/basicSize)向上取整的哈希算法快速找到对应内存块。

通过伙伴系统管理空闲分区的了解,可以看到在伙伴系统中的每条空闲分区链中挂的都是2i的页面大小,通过哈希思想进行空间分配与合并,非常高效。估计可能是这个原因SGI-STL选择以2倍方式进行扩容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值