STL等容器使用时,需做规格预估与预留,避免容器内存自动扩张
【说明】 主要针对std::vector和std::string或者类似的内存连续的顺序型容器。针对这种类型的容器插入大量数据之前,可以对容器的规格进行预留,避免容器因内存不足自动扩张内存带来的性能影响。
【原理】 内存连续的顺序型容器的内存是自动管理的,按需扩张。在数据插入过程中出现内存耗尽的情况,容器会重新申请一块更大的内存空间,然后把当前的每一个元素拷贝到新的地址,再释放原来的内存,最后在插入新的元素。在内存的扩张过程中,会产生大量耗时操作,如内存申请和释放、数据的拷贝等。因此如果能提前知道规格,可以提前设置规格,就能避免频繁的扩张。
【注意事项】 提前预留规格,可能导致内存的利用率降低,需要在空间与时间之间做好权衡。
【案例】
优化前:
std::vector<uint32_t> GetKeyOfMap(const std::map<uint32_t,uint32_t> &map)
{
std::vector<uint32_t> vec;
for(auto &item : map){
vec.emplace_back(item.first);
}
return vec;
}
说明:当map的数量比较多少时, vec变量会多次扩张,可能出现8->16->32->64.....->1024等多次扩张(内存申请释放)和多次的内存拷贝。如果使用reserve函数为vec预留内存,就可以节省多次扩张和拷贝。
优化后:
std::vector<uint32_t> GetKeyOfMap(const std::map<uint32_t,uint32_t> &map)
{
std::vector<uint32_t> vec;
vec.reserve(map.size());
for(auto &item : map){
vec.emplace_back(item.first);
}
return vec;
}
需要特别说明的是,vector多次扩张带来内存空洞浪费,在未关闭异常处理时,是可以使用操作shrink_to_fit释放掉未使用的内存,以避免内存浪费的。
父主题: C++语言