3

我想使用 std::deque,但是消耗的内存开销似乎太大了。我做错了什么吗?

#include "windows.h"
#include "psapi.h"

#include <iostream>
#include <vector>
#include <queue>

int main (int, char* [])
{
    PROCESS_MEMORY_COUNTERS pm;
    GetProcessMemoryInfo(GetCurrentProcess(), &pm, sizeof(pm));
    size_t mem1 = pm.WorkingSetSize;

    std::vector<int> v( 10000000 );

    GetProcessMemoryInfo(GetCurrentProcess(), &pm, sizeof(pm));
    size_t mem2 = pm.WorkingSetSize;

    std::deque<int> q( 10000000 );
    GetProcessMemoryInfo(GetCurrentProcess(), &pm, sizeof(pm));
    size_t mem3 = pm.WorkingSetSize;

    std::cout << mem2 - mem1 << std::endl;
    std::cout << mem3 - mem2 << std::endl;

    return 0;
}

输出(在 32 位 Windows 系统上):

40087552
72564736

奖金问题:为什么 mem2 - mem1 不完全是 40000000?

4

2 回答 2

4

我不认为双端队列分配在连续的内存块中。来自(http://www.cplusplus.com/reference/deque/deque/):

向量和双端队列都提供了非常相似的接口并且可以用于相似的目的,但在内部两者的工作方式完全不同:虽然向量使用单个数组,需要偶尔重新分配以实现增长,但双端队列的元素可以分散在不同的存储块,容器在内部保存必要的信息,以在恒定时间内提供对其任何元素的直接访问,并具有统一的顺序接口。因此,双端队列在内部比向量复杂一点,但这允许它们在某些情况下更有效地增长,特别是对于非常长的序列,其中重新分配变得更加昂贵。

于 2013-05-24T20:39:12.580 回答
2

如前所述, adeque不是在连续的内存块中分配的。它必须保留数据以跟踪内存块的位置。具体细节取决于实现,但可以在STL 内部找到一些细节:双端队列实现

工作集是正在使用的物理内存量。来自工作集文档。

进程的工作集是进程的虚拟地址空间中当前驻留在物理内存中的页面集。

有可能一些内存已被分页到磁盘,这增加了差异。

有几个原因mem2 - mem1不等于 40000000。简单地说,std::vector对象可能有额外的成员变量。它可以跟踪大小变量以及开始和结束迭代器。另一个原因是 Windows 堆也需要跟踪它的内存,这需要内存来做到这一点。

管理堆内存

但实际上,堆管理器需要额外的内存来管理堆中的内存。因此,它不是按要求只分配 100 个字节,而是分配一些空间来管理每个特定的内存块。内存的类型和分配的大小决定了这个额外内存的大小。

你可以试试这个,通过替换std::vector<int>with int* v = new int[10000000];,你会看到内存差异超过 40000000 字节。

于 2013-05-24T21:02:29.423 回答