使用std::map和std::list存放数据,消耗内存比实际数据大得多

场景:项目中需要存储一个结构,如下程序段中TEST_DATA_STRU,结构占24B。但是使用代码中的std::list<DataListMap>类存储4000个DataListMap,每个DataListMap中有4个pairs,每个pair中的DataList中有6000个items时,消耗掉的内存几乎是我们存放TEST_DATA_STRU的2倍。

#include <iostream>
#include <map>
#include <list>
#include <vector> typedef struct TEST_DATA_STRU
{
int Data_A;
int Data_B;
int Data_C;
int Data_D;
}TEST_DATA_STRU; typedef std::list<TEST_DATA_STRU> DataList;
typedef std::map<int, DataList> DataListMap; int main(int argc, char **argv)
{
std::cout << "create a map" << std::endl;
DataListMap dataListMap;
// there are 100 pairs in the dataListMap
for(int i=0; i<100; ++i)
{
DataList dataList;
// there are 1000 items in a dataList
for(int j=0; j<1000; ++j)
{
TEST_DATA_STRU testStru = {i, j, i+j, i-j};
dataList.push_back(testStru);
}
dataListMap.insert(make_pair(i, dataList));
} std::cout << "data size of DataListMap: " << sizeof(TEST_DATA_STRU) * 1000 + sizeof(int) * 100 << std::endl; std::cout << "testing..." << std::endl;
std::list<DataListMap> mapList;
for(int i=0; i<4000; ++i)
{
mapList.push_back(dataListMap);
} // finally the memory of mapList is about double of the data we want to save
return 0;
}

最后通过分析,排除了内存泄露等情况后,将原因锁定在DataListMap类上。进一步分析后才找到原因:我们存放的结构占用24B,但是std::map和std::list中的指针就会占用24B以上,所以最终std::map和std::list自身所需的内存几乎和我们存储的数据一样大,甚至更大。

深入分析:std::list和std::map属于散列容器,容器的空间之间是通过指针来关联的,所以指针会占用一部分内存,当自身存放的数据较2*8(std::list,双向链表)差别不大时,会有很大的额外内存开销。为了避免此开销,可以使用线性容器,std::vector。

修改代码如下:使用std::vector取代std::list

#include <iostream>
#include <map>
#include <list>
#include <vector> typedef struct TEST_DATA_STRU
{
int Data_A;
int Data_B;
int Data_C;
int Data_D;
}TEST_DATA_STRU; typedef std::list<TEST_DATA_STRU> DataList;
typedef std::map<int, DataList> DataListMap; typedef std::vector<TEST_DATA_STRU> DataVec;
typedef std::map<int, DataVec> DataVecMap; int main(int argc, char **argv)
{
std::cout << "create a map" << std::endl;
//DataListMap dataListMap;
DataVecMap dataVecMap;
// there are 100 pairs in the dataListMap
for(int i=0; i<100; ++i)
{
//DataList dataList;
DataVec dataVec;
dataVec.reserve(1000);
// there are 1000 items in a dataList
for(int j=0; j<1000; ++j)
{
TEST_DATA_STRU testStru = {i, j, i+j, i-j};
//dataList.push_back(testStru);
dataVec.push_back(testStru);
}
//dataListMap.insert(make_pair(i, dataList));
dataVecMap.insert(make_pair(i, dataVec));
} std::cout << "data size of DataListMap: " << sizeof(TEST_DATA_STRU) * 1000 + sizeof(int) * 100 << std::endl; std::cout << "testing..." << std::endl;
//std::list<DataListMap> mapList;
std::list<DataVecMap> mapList;
for(int i=0; i<4000; ++i)
{
//mapList.push_back(dataListMap);
mapList.push_back(dataVecMap);
} // finally the memory of mapList is almost same with the data we want to save
return 0;
}

最终省去了额外的内存开销。

记于2016.04.14 22:28:24。

使用std::map和std::list存放数据,消耗内存比实际数据大得多的更多相关文章

  1. 有关std::map和std::vector的使用

    先说map吧. 最需要注意的就是:用下标访问map中的元素时,与使用下标访问vector的行为截然不同! 用下标访问不存在的元素时,将导致在map容器中添加一个新的元素,它的键即为该下标! 然而很多时 ...

  2. C++ std::map用法简介

    #include "map" //引入头文件 初始化: std::map <int, std::string> _map1; //初始化 //c++11中引入的,可以直 ...

  3. C++ | 使用const std::map,map::[]时遇到的一个bug

    原函数简化后如下: void fun(const map<int,vector<int>> &mp, int index) { for (auto tmp : mp[i ...

  4. 基于Python项目的Redis缓存消耗内存数据简单分析(附详细操作步骤)

    目录 1 准备工作 2 具体实施   1 准备工作 什么是Redis? Redis:一个高性能的key-value数据库.支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使 ...

  5. 【EF学习笔记05】----------操作内存中的数据

    SingleOrDefault实验 //SingleOrDefault实验 using (var db = new Entities()) { var classes = new Classes() ...

  6. js中数据、内存、变量的概念及三者之间的关系

    目录 数据.内存.变量的概念及三者之间的关系 什么是数据 数据的特点 什么是内存 栈内存 堆内存 JS引擎如何管理内存 什么是变量 变量是普通类型时 变量是引用类型时 数据.内存.变量的三者之间的关系 ...

  7. std::map用法

    STL是标准C++系统的一组模板类,使用STL模板类最大的好处就是在各种C++编译器上都通用.    在STL模板类中,用于线性数据存储管理的类主要有vector, list, map 等等.本文主要 ...

  8. C++ std::map::erase用法及其陷阱

    1.引入: STL的map中有一个erase方法用来从一个map中删除制定的节点 eg: map<string,string> mapTest; typedef map<string ...

  9. std::map的clear()没有用?

    昨天晚上,我徒弟跑过来讲,他的程序的内存占用居高不下,愿意是std::map的clear()没有效果.于是我让他用erase(begin,end); 试试也不行. 代码如下: void release ...

随机推荐

  1. php &符的写法

    foreach ($expert as &$value) { $value['z_thumbs'] = $_W['attachurl'].$value['z_thumbs']; } forea ...

  2. 基于VMware模拟实现远程主机网络通信

    基于VMware模拟实现远程主机网络通信 目的: 基于VMware软件,模拟实现不同网段的两主机,通过路由器进行通信.两主机host A和host B分别处于VMnet6网络和VMnet7网络,都属于 ...

  3. CentOS6.8下实现配置配额

    CentOS6.8下实现配置配额 Linux系统是支持多用户的,即允许多个用户同时使用linux系统,普通用户在/home/目录下均有自己的家目录,在默认状态下,各个用户可以在自己的家目录下任意创建文 ...

  4. Financiers Game CodeForces - 737D (博弈论)

    直接暴力区间DP的话是$O(n^3)$, 关键注意到每步走的距离差不超过1, 所以差最大是$O(\sqrt{n})$的, 所以实际上有用的状态是$O(n^2)$的, 可以通过.

  5. Non-UTF-8 code starting with '\xbb' in file

    一.错误问题 错误问题:Non-UTF-8 code starting with '\xbb' in file,如图所示: 二.分析问题 原因:程序文件夹中出现中文,运行的时候出现如下错误,导致出错的 ...

  6. ATOM常用插件推荐

    转载:http://blog.csdn.net/qq_30100043/article/details/53558381 ATOM常用插件推荐 simplified-chinese-menu ATOM ...

  7. Leetcode 98

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

  8. MySQL Workbench中如何开启MySQL的远程帐号

    '; /* 上面的语句表示将 discuz 数据库的所有权限授权给 root这个用户,允许 root用户在192.168.119.120进行远程登陆,并设置 root用户的密码为 123456 . 下 ...

  9. python中的apscheduler模块

    1.简介 apscheduler是python中的任务定时模块,它包含四个组件:触发器(trigger),作业存储(job store),执行器(executor),调度器(scheduler). 2 ...

  10. [洛谷 P3788] 幽幽子吃西瓜

    妖梦费了好大的劲为幽幽子准备了一个大西瓜,甚至和兔子铃仙打了一架.现在妖梦闲来无事,就蹲在一旁看幽幽子吃西瓜.西瓜可以看作一个标准的球体,瓜皮是绿色的,瓜瓤是红色的,瓜皮的厚度可视为0.妖梦恰好以正视 ...