You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::map调用clear()耗时过长的原因及优化方案咨询

问题描述

我创建了一个存储自定义结构体的大型std::map,该结构体包含多个std::vector成员。调用该map对象的clear()方法时耗时极长。

我运行的示例代码占用了超过80%的内存,我怀疑交换内存与此问题有关,但即便如此,我仍不清楚为何删除std::map的内容需要这么长时间。

能否有人告知这是怎么回事?

以下是示例代码,在我的机器上运行耗时约100秒(波动较大):

#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <chrono>

struct MyStruct {
    std::vector<int64_t> vi01;
    std::vector<int64_t> vi02;
    std::vector<int64_t> vi03;
    std::vector<int64_t> vi04;
    std::vector<int64_t> vi05;
    std::vector<int64_t> vi06;
    std::vector<int64_t> vi07;
    std::vector<int64_t> vi08;
    std::vector<int64_t> vi09;
    std::vector<int64_t> vi10;
    std::vector<int64_t> vi11;
    std::vector<int64_t> vi12;
    std::vector<int64_t> vi13;
    std::vector<int64_t> vi14;
    std::vector<int64_t> vi15;
    std::vector<int64_t> vi16;
    std::vector<int64_t> vi17;
    std::vector<int64_t> vi18;
    std::vector<int64_t> vi19;
    std::vector<int64_t> vi20;

    std::vector<std::string> vs01;
    std::vector<std::string> vs02;
    std::vector<std::string> vs03;
    std::vector<std::string> vs04;
    std::vector<std::string> vs05;
    std::vector<std::string> vs06;
    std::vector<std::string> vs07;
    std::vector<std::string> vs08;
    std::vector<std::string> vs09;
    std::vector<std::string> vs10;
    std::vector<std::string> vs11;
    std::vector<std::string> vs12;
    std::vector<std::string> vs13;
    std::vector<std::string> vs14;
    std::vector<std::string> vs15;
    std::vector<std::string> vs16;
    std::vector<std::string> vs17;
    std::vector<std::string> vs18;
    std::vector<std::string> vs19;
    std::vector<std::string> vs20;
};

int main() {

    std::map<std::string, MyStruct> sId_MyStruct{};

    // roughly 500 * 7'000 * 2'000 = 7'000'000'000 bytes (7GB)
    // but std::vector's capacity() would be bigger.
    for (int64_t i=10'000ULL; i < 10'000ULL+7'000ULL ; ++i) {
        
        std::string sId = std::to_string(i);
        MyStruct & myStruct = sId_MyStruct[sId];

        for (int64_t j=10'000ULL; j<(10'000ULL+2'000ULL); ++j) {
            // Figures for simple reference only. 
            // Not considered the actual capacity of the vectors.

            // 8 bytes per element x 20 = 160 bytes.
            myStruct.vi01.push_back(j);
            myStruct.vi02.push_back(j);
            myStruct.vi03.push_back(j);
            myStruct.vi04.push_back(j);
            myStruct.vi05.push_back(j);
            myStruct.vi06.push_back(j);
            myStruct.vi07.push_back(j);
            myStruct.vi08.push_back(j);
            myStruct.vi09.push_back(j);
            myStruct.vi10.push_back(j);
            myStruct.vi11.push_back(j);
            myStruct.vi12.push_back(j);
            myStruct.vi13.push_back(j);
            myStruct.vi14.push_back(j);
            myStruct.vi15.push_back(j);
            myStruct.vi16.push_back(j);
            myStruct.vi17.push_back(j);
            myStruct.vi18.push_back(j);
            myStruct.vi19.push_back(j);
            myStruct.vi20.push_back(j);

            // 15 bytes(string's capacity) per element x 20 = 300bytes.
            std::string sj = std::to_string(j);
            myStruct.vs01.push_back(sj);    
            myStruct.vs02.push_back(sj);    
            myStruct.vs03.push_back(sj);    
            myStruct.vs04.push_back(sj);    
            myStruct.vs05.push_back(sj);    
            myStruct.vs06.push_back(sj);    
            myStruct.vs07.push_back(sj);    
            myStruct.vs08.push_back(sj);    
            myStruct.vs09.push_back(sj);    
            myStruct.vs10.push_back(sj);
            myStruct.vs11.push_back(sj);
            myStruct.vs12.push_back(sj);
            myStruct.vs13.push_back(sj);
            myStruct.vs14.push_back(sj);
            myStruct.vs15.push_back(sj);
            myStruct.vs16.push_back(sj);
            myStruct.vs17.push_back(sj);
            myStruct.vs18.push_back(sj);
            myStruct.vs19.push_back(sj);
            myStruct.vs20.push_back(sj);
        }

        if (i % 1'000 == 0)
            std::cout << "sId:" << sId << std::endl;
    }

    std::cout << "std::map object creation finished." << std::endl;
    std::cout << "press anything and enter to continue.";
    std::string sIn;
    std::cin >> sIn;
    //std::cout << sIn << '\n';

    std::cout << "std::map clear() start." << std::endl;

    auto beg = std::chrono::steady_clock::now();
    sId_MyStruct.clear();
    auto fin = std::chrono::steady_clock::now();

    auto dur = fin - beg;
    auto sec = (dur).count() / 1'000'000'000;
    std::cout << sec << " seconds taken." << std::endl;

    std::cout << "======main fin=======" << std::endl;

}

这是相关问题的后续提问,因要求提供最小可复现示例而发布。

后续测试结论

阅读评论和回答后,我进行了不同配置的额外测试,得出以下结论:

  • 操作系统与磁盘的内存交换并非直接原因,即使内存(RAM)占用不高(约40%)时,clear()仍耗时较久。
  • std::map的clear()与std::unordered_map的clear()性能差异显著,尤其是在仅使用int64_t作为vector元素类型时。
  • 将vector元素类型从std::string改为int64_t可提升clear()性能,符合预期,但提升幅度不大。
  • 未来优化方向:
    1. 避免堆分配;
    2. 若使用堆分配,采用“扁平”数据结构;
    3. 编写自定义分配器。
额外测试结果

(结果因机器、配置等不同而异,仅供参考)

  • 使用std::map(与原配置一致)
    1. 共40个vector<int64_t>,无vector<string>:耗时减少约30%(约70秒)。
    2. 共60个vector<int64_t>,无vector<string>:耗时增加约40%(约140秒)。
  • 使用std::unordered_map替代std::map
    1. 共20个vector<int64_t>和20个vector<string>(与原std::map配置一致):耗时减少约5%(约96秒)。
    2. 共40个vector<int64_t>,无vector<string>:耗时减少约70%(约30秒)。
    3. 共60个vector<int64_t>,无vector<string>:耗时减少约40%(约64秒)。

内容的提问来源于stack exchange,提问作者starriet 차주녕

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:19:51