GCC c++11 使用大量 RAM 和 STL 位集<UINT_MAX>
GCC c++11 using a lot of RAM with STL bitset<UINT_MAX>
今天编译我的程序时,我注意到GCC(编译步骤(的内存消耗模式中有一些非常奇怪的东西(我相信可以以某种方式解释(。名为"cc1plus"的进程对代码少于 10,000 行的程序使用大约 10 GB 的 RAM。在注释和取消注释代码行之后,我终于找到了"罪魁祸首":
std::bitset<UINT_MAX>
如果你想测试自己,请尝试这个非常短的程序:
#include <iostream>
#include <bitset>
#include <climits>
std::bitset<UINT_MAX> justAVar;
int main()
{
std::cout << UINT_MAX << std::endl;
return 0;
}
使用 -std=c++11 或 -std=c++0x 编译它请注意,即使是这个小例子在编译时也会使用大量 RAM(在我的情况下,GCC 的两个盒子上都有 7 GB,clang 的两个盒子上都有 2.6 GB(,所以如果你必须按下重置按钮,不要抱怨和诅咒众神,就像你没有被警告过一样。
我的测试机器:
设置 1: Debian 7.0 64, gcc 4.8.1
设置 2:Ubuntu 12.04 64、gcc 4.7.3、gcc 4.8.1、clang 3.0.6(最后一个使用 -std=c++0x(
关于位集构造函数实现的一个提示(显然由 if def 保护 C++11 和 C++0x(,正如我的一位同事向我展示的那样:它是使用 constexpr 声明
的现在的问题是:有人可以解释一下我(我们(在这种情况下所有这些编译器是怎么回事吗?
谢谢
查看bitset
实现,其开头如下所示:
template<size_t _Nw>
struct _Base_bitset
{
typedef unsigned long _WordT;
_WordT _M_w[_Nw];
constexpr _Base_bitset()
: _M_w() { }
我们可以创建一个最小的测试用例,如下所示:
template<unsigned N>
struct bset
{
unsigned int v[N/32];
constexpr bset() : v() {}
};
bset<1000000000> x;
位集必须通过常量初始化来初始化:
在3.6.2 非局部变量的初始化 [basic.start.init]
。
执行常量初始化:
。
— 如果初始化了具有静态或线程存储持续时间的对象 通过构造函数调用,如果构造函数是 constexpr 构造 函数。。。
实际术语和一般情况下,它意味着在编译时评估构造对象的内存映像并将其分配给.data
部分。
好吧,事实证明,如果内存图像只是很多零,gcc 足够聪明,可以弄清楚并在 .bss
中分配对象,但看起来,它首先必须创建图像并检查它。
当然,更好的方法是推断,如果bitset
的唯一成员是值初始化的,并且该成员是一个数组,并且数组的元素没有构造函数,因此它们的值初始化是零初始化,然后数组是零初始化的,那么对象是零初始化的,然后完成。
std::bitset
不会动态分配其存储,它包含在对象本身中。这意味着编译器很可能尝试跟踪其状态,以允许常量折叠和其他优化。在某些地方使用constexpr
的事实也促成了这一点。这包括跟踪bitset
各个部分价值的一些开销,将导致它分配数吨的内部结构。
我不确定在哪些情况下会触发此功能,并且在不同的编译器/版本上可能会有所不同,或者取决于某些设置。
UINT_MAX
在大多数现代机器上约为40亿。由于std::bitset<N>
存储N
位,因此这转化为这种std::bitset
所需的0.5千兆字节内存(40亿/8(。您看到的开销可能是由于内部编译器优化造成的。
http://coliru.stacked-crooked.com/的一些小实验:
- Clang -std=c++98: OK
- Clang -std=c++11: FAIL
- g++ -std=c++98: FAIL
- g++ -std=c++11: FAIL
因此,至少对于 Clang 来说,C++98 中缺少constexpr
将允许您在合理的资源上编译该程序而不会出现问题(不确定 Coliru 允许客户端多少内存(。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- GLSL 将 uint 转换为浮点颜色
- 定义 uint= "unsigned int" 没有像我在 Visual Studio 中使用 nvcc 时预期的那样应用
- 着色器将uint8投射到float,并将其重新解释回uint
- 如何显式调用运算符<<
- 如何将boost::asio::ip::address_v6 ip转换为2个uint64_t数字,并从2个uint 64
- 将 CRC uint 转换为 QByteArray QT - C++
- 模板操作员&lt;未打电话
- C / CUDA中的模板方法是3个角括号(&lt;&lt;&lt;)
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 错误:调用"std::vector<:vector<int>>::p ush_back(std::vector<std::__cxx11::basic_string<
- C 建造者Clang STD :: Sill,找不到超载的操作员&lt;
- 为什么STD :: MAP需要操作员&lt;以及我如何写一个
- OSX 上的 GCC 5、6 和 7 不支持 uint
- 为什么“操作员”需要const但不是为“运营商&lt;”
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- Multiplication: uint vs float