unordered_map在VS10中抛出bad_alloc但在VS9中没有抛出,这是一个错误吗?

时间:2010-07-07 12:43:01

标签: c++ visual-studio-2008 visual-studio-2010 unordered-map

虽然writing a post关于project euler's 14th problem但我遇到了VC9和VC10之间的行为差​​异。

以下代码在VC9中运行正常,但在VC10 std::unordered_map中抛出bad_alloc异常。 奇怪的是,如果我从异常中恢复,未来的分配将成功(容器的大小继续增长)。此外,如果我使用boost::unordered_map,它在两个编译器中都可以正常工作。

关于实际的内存使用情况,我在运行4GB RAM的机器上运行(1.7使用中),VC9版本在完成任务之前可以达到~810MB的内存,VC10的内存在~658MB崩溃。

这是VC10中的错误吗?我在同一台机器上运行还有什么可能导致内存在一个版本中持续耗尽,而在完成的工作量相同时则不会在另一个版本中耗尽?

<子>&LT;编辑&gt;
更多信息:第一次发生异常是计算7,718,688时堆栈深度为1(没有递归只是main-&gt; length)。之后,似乎会发生添加到缓存中的每个数字。在异常发生之前,缓存中有16,777,217个元素(根据cache.size())。有趣的是,即使insert失败,缓存大小也会增加1,因此它似乎不提供强异常保证(违反§23.2.1.11)。
<子>&LT; /编辑&gt;

代码如下:

#include <iostream>
#include <unordered_map>

typedef std::unordered_map<_int64, int> cache_type;

_int64 collatz(_int64 i)
{
    return (i&1)? i*3+1 : i/2;
}

int length(_int64 n, cache_type& cache)
{
    if (n == 1)
        return 1;

    cache_type::iterator found = cache.find(n);
    if (found != cache.end())
        return found->second;
    int len = length(collatz(n), cache) + 1; 
    cache.insert(std::make_pair(n, len)); // this sometimes throws
    return len;
}

int main(int argc, char** argv)
{
    const int limit = 10000000;
    cache_type cache;
    std::pair<int, int> max = std::make_pair(0, 0);
    for (int i = 2; i <= limit; ++i) {
        int len = length(i, cache);
        if (len > max.second)
            max = std::make_pair(i, len);
    }

    std::cout<< "Number with longest orbit is " << max.first 
        << " with a lenght of " << max.second 
        << " cache size is " << cache.size() << std::endl;
}

<子>&LT;编辑&gt;
任何人都可以重现这种行为,有一次它会消失(并重新出现),所以我的配置可能有些特别之处。
<子>&LT; /编辑&gt;

5 个答案:

答案 0 :(得分:2)

这可能是偶然的,但更改_SECURE_SCL的值会导致您描述的行为。

即编译:

cl /EHa /MD /D_SECURE_SCL=1 /Ox /c t1.cpp
link /LIBPATH:"c:/Program Files/Microsoft Visual Studio 10.0/VC/lib" /LIBPATH:"C:/Program Files/Microsoft SDKs/Windows/v7.0A/Lib" t1.obj

崩溃了,但是在我的XP 32bit机器上,_SECURE_SCL = 0的相同命令运行完毕。 _SECURE_SCL的msdn页面表示已启用调试版本,但未启用版本,如果您在IDE下构建,这可能很重要。

答案 1 :(得分:1)

如果需要调整地图的哈希表大小,插入单个元素可能会导致大量内存分配。在运行结束时,地图似乎约为0.5GB。 (见上面的评论。)

可能有一些启发式用于决定在需要增长时扩展哈希表的程度,这可以想象每次都要加倍。因此,在复制哈希表时,这将使用~1.5GB的旧+新数据。

因此,您的程序可能会限制进程内存大小。 (再次参见注释。)如果是这样,VC10可能会占用比VC9更多的内存,并且在程序的不同运行或构建上分配稍微不同的内存量,因此VC10有时会达到限制,而VC9不会曾经打过它。

答案 2 :(得分:0)

_int64是否具有地图可能不符合分配条件的对齐要求?

尝试使用long long int来查看行为是否发生变化。

答案 3 :(得分:0)

你在对length()的深度递归调用中吹嘘堆栈。

答案 4 :(得分:0)

1 - 检查EventLog以查看是否有任何事件正在讨论一个流程超过允许的配额。

2 - 如果您使用的是32位操作系统,请尝试使用3GB的用户空间启动它。

3 - 查看您是否有不同的分配器

4 - 9.0和10.0中的Diff unordered_map,并且它的内联文件中有一个人为大小的限制器(“安全功能”:-)。它很可能是在x86和x64构建的不同值的宏中。

5 - 尝试在分配器周围放置一个光包装器,并为每个分配打印大小。这也会告诉你它是真正的分配器还是扔掉它之前的东西。

6 - 如果是分配器抛出看看从它做的实际WinNT API调用(再次使用9.0的差异)

7 - 尝试预先分配大块(比如1 GB)。