2

我有一个自动生成的 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;对我有用。

4

6 回答 6

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()调用的大型函数。

于 2009-11-30T00:02:57.813 回答
1

你能在不生成 40 MB 的 C++ 的情况下做同样的问题吗?这不仅仅是我使用过的一些操作系统。也许是一个循环和一些数据文件?

于 2009-11-30T00:04:17.907 回答
1

听起来您的自动生成的应用程序如下所示:

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

为什么不把数据放到一个外部文件中,让程序循环读取这些数据呢?

于 2009-11-30T00:04:53.130 回答
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));
}

whereARRAYCOUNT是一个宏定义如下:

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

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

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

于 2009-11-30T00:05:15.707 回答
0

为了补充这里的一些答案,您最好生成一个二进制对象文件并直接链接它——而不是编译由const char[]'s.

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

于 2009-11-30T00:21:40.850 回答
0

如果您无法重构代码,则可以尝试增加您拥有的交换空间量,前提是您的操作系统支持大地址空间。这应该适用于 64 位计算机,但 3 GB 可能对于 32 位系统来说太大了。

于 2009-11-30T01:38:01.283 回答