gcc / g ++:编译大文件时出错

时间:2009-11-29 23:54:11

标签: gcc g++ compilation large-files

我有一个自动生成的C ++源文件,大小约为40 MB。它主要包括一些向量的push_back命令和应该被推送的字符串常量。

当我尝试编译此文件时,g ++退出并说它无法保留足够的虚拟内存(大约3 GB)。谷歌搜索这个问题,我发现使用命令行开关

--param ggc-min-expand=0 --param ggc-min-heapsize=4096

可以解决问题。但是,它们在启用优化时似乎才起作用。

1)这真的是我正在寻找的解决方案吗?

2)或者是否有更快,更好(编译需要很长时间才能使用这些选项)这样做?

祝福,

亚历山大

更新:感谢所有好主意。我尝试了大部分。使用数组而不是几个push_back()操作减少了内存使用量,但由于我尝试编译的文件太大,它仍然崩溃,只是在以后。在某种程度上,这种行为非常有趣,因为在这样的设置中没有太多优化 - GCC在幕后做了多少内存? (我编译时也停用了所有优化并得到了相同的结果)

我现在切换到的解决方案是使用objcopy从原始文件创建的二进制对象文件中读取原始数据。这是我最初不想做的事情,因为用更高级语言(在本例中为Perl)创建数据结构比在C ++中执行此操作更方便。

然而,在Win32下运行这个比预期更复杂。 objcopy似乎以ELF格式生成文件,当我手动将输出格式设置为pe-i386时,似乎我消失了一些问题。目标文件中的符号是按文件名命名的标准,例如,转换文件inbuilt_training_data.bin将导致这两个符号:binary_inbuilt_training_data_bin_start和binary_inbuilt_training_data_bin_end。我在网上发现了一些声明这些符号应该声明为extern char _binary_inbuilt_training_data_bin_start;的教程,但这似乎不对 - 只有extern char binary_inbuilt_training_data_bin_start;对我有效。

6 个答案:

答案 0 :(得分:4)

您可能最好使用常量数据表。例如,而不是这样做:

void f() {
    a.push_back("one");
    a.push_back("two");
    a.push_back("three");
    // ...
}

尝试这样做:

const char *data[] = {
    "one",
    "two",
    "three",
    // ...
};

void f() {
    for (size_t i = 0; i < sizeof(data)/sizeof(data[0]); i++) {
        a.push_back(data[i]);
    }
}

编译器可能会更有效地生成一个大型常量数据表,而不是包含许多push_back()次调用的大型函数。

答案 1 :(得分:1)

如果不生成40 MB的C ++,你能解决同样的问题吗?这比我使用的一些操作系统更重要。一个循环和一些数据文件,也许?

答案 2 :(得分:1)

听起来你的自动生成的应用程序看起来像这样:

push_back(data00001);
...
push_back(data99999);

为什么不将数据放入外部文件并让程序循环读取这些数据?

答案 3 :(得分:0)

如果您只是连续产生了对push_back()的调用,您可以将其重构为以下内容:

// Old code:
v.push_back("foo");
v.push_back("bar");
v.push_back("baz");

// Change that to this:
{
    static const char *stuff[] = {"foo", "bar", "baz"};
    v.insert(v.end(), stuff, stuff + ARRAYCOUNT(stuff));
}

其中ARRAYCOUNT是一个定义如下的宏:

#define ARRAYCOUNT(a) (sizeof(a) / sizeof(a[0]))

额外的大括号只是为了避免名称冲突,如果你有很多这样的块;或者,您可以为stuff占位符生成新的唯一名称。

如果仍然无效,我建议将您的源文件分解为许多较小的源文件。如果你有许多独立的功能,这很容易;如果你有一个巨大的功能,你将需要更努力地工作,但它仍然非常可行。

答案 4 :(得分:0)

为了补充这里的一些答案,你可能最好生成二进制目标文件并直接链接它 - 而不是编译由const char[]组成的文件。

我最近在使用gcc时遇到了类似的问题。 (大约60 MB的PNG数据分成大约100个头文件。)包括它们都是最糟糕的选择:所需的内存量似乎随着编译单元的大小呈指数级增长。

答案 5 :(得分:0)

如果您无法重构代码,只要操作系统支持大地址空间,您就可以尝试增加交换空间量。这适用于64位计算机,但对于32位系统,3 GB可能太多了。