【问题标题】:C++11: g++-4.7 internal compiler errorC++11:g++-4.7 内部编译器错误
【发布时间】:2012-10-27 19:23:03
【问题描述】:

以下代码:

#include <iostream>
#include <array>
using namespace std;

constexpr int N = 1000000;
constexpr int f(int x) { return x*2; }

typedef array<int, N> A;

template<int... i> struct F { static constexpr A f() { return A{{ ::f(i)... }}; } };

template<class A, class B> struct C {};
template<int... i, int... j> struct C<F<i...>, F<j...>> : F<i..., (sizeof...(i)+j)...>
{
        using T = F<i..., (sizeof...(i)+j)...>;
};

template<int n> struct S : C<typename S<n/2>::T, typename S<n-n/2>::T> {};
template<> struct S<1> : F<0> { using T = F<0>; };

constexpr auto X = S<N>::f();

int main()
{
        cout << X[3] << endl;
}

-std=gnu++11 模式下的 GCC 4.7 中产生内部编译器错误。

$ g++ -std=gnu++11 test.cpp
g++-4.7.real: internal compiler error: Killed (program cc1plus)

出了什么问题?

【问题讨论】:

  • 在 4.7.1 我有cc1plus: out of memory allocating 1048576 bytes after a total of 401997824 bytes。看起来像一个编译器错误。
  • 我在 4.7.2 并且有 32GB 的内存。这些都可以解释差异。
  • 可能是因为这里有 8 GB 但是当减小 N 的值时它会正确编译。

标签: c++ linux gcc c++11 g++


【解决方案1】:

您的程序似乎需要不合理的内存量(可能是因为模板扩展过多)。

使用最近的g++-trunk

gcc version 4.8.0 20121026 (experimental) [trunk revision 192860] (GCC) 

具有以下 zsh 限制:

   % limit          
   cputime         unlimited
   filesize        unlimited
   datasize        15000MB
   stacksize       8MB
   coredumpsize    400MB
   memoryuse       15000MB
   maxproc         128166
   descriptors     1024
   memorylocked    64kB
   addressspace    16000MB
   maxfilelocks    unlimited
   sigpending      128166
   msgqueue        819200
   nice            0
   rt_priority     0
   rt_time         unlimited

(在 Debian/Sid/AMD64 上使用 i3770K 英特尔处理器和 16Gb RAM)

我得到:

  % time g++-trunk -std=gnu++11 andrew.cc -o andrew
  virtual memory exhausted: Cannot allocate memory
  g++-trunk -std=gnu++11 andrew.cc -o andrew :
  108.25s user 3.28s system 89% cpu 2:03.98 total

所以看来模板扩展需要这么多内存,你编程是不合理的。

我不确定这是否会被视为 GCC 错误。众所周知,C++ 模板的宏扩展是图灵完备的,而您只是碰壁了。并且 GCC 中继确实报告了一个致命但可以理解的错误。

故事的寓意可能是适当地使用setrlimit(2)(限制与您的系统和硬件兼容),可能使用内置的limit zsh 或内置的ulimit bash。

【讨论】:

  • 我很想知道 ~10^6 扩展究竟是如何耗尽 32GB 内存的。递归深度很小,否则会达到512深度限制。它适用于 N=10000,所以它看起来好像在使用 O(N^2) 空间,但它应该只使用 O(NlogN) 空间。
  • 原因很简单:编译器希望(并且对于大多数用户来说应该)在其内部表示中保留大量数据。所以实际的扩展发生在内部表示(Gcc Generic)上,这比你想象的更复杂(例如,因为它记住了每件事的源位置)。
  • 记住源位置不足以解释资源需求的渐近增长。对于像这个 GCC 一样大的持续爆炸,每次实例化需要大约 32kb,这是荒谬的。
  • 那么请通过提交相关补丁为GCC做出贡献。
  • clang++ 编译这个(在增加 -fconstexpr-steps 之后)在大约 1.5G 的内存中没有问题,在 10 秒内。 g++ 增长到 15G 并在约 4 分钟后被杀死。 (是的,这些年来它仍然这样做)。
【解决方案2】:

内部错误意味着您遇到了编译器错误。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 2012-05-08
  • 1970-01-01
  • 2018-05-12
  • 2013-03-13
相关资源
最近更新 更多