我正在使用很多模板进行C ++大学研究项目,这些模板还有其他嵌套模板等等。该项目涉及特定研究领域的有效指数数据结构。你可以想象:索引结构有很多参数要调整,所以我们过度使用模板参数。当然,我们希望使用不同的参数集测试我们的索引,因此有很多模板实例化。
项目不是那么大。也许50k LOC。但是,链接需要50秒,消耗超过7 GB的内存(!!!)。我在32GB的工作站上,所以一切都很好。我经常有从事这个项目的学士和硕士生。问题是他们经常使用4或8 GB RAM的笔记本电脑。因此,这些学生在编写该项目时遇到了很大麻烦。得到的测试二进制文件(即仅包含索引结构的单元测试的二进制文件)是700兆字节。
其中大多数是符号,因为嵌套模板会产生巨大的名称。如果我在二进制文件上使用strip
,它会下降到8兆字节。
那么有没有办法减少链接期间的RAM使用量?有没有办法在嵌套模板中使用较小的符号?
我们在Ubuntu 14.10下使用g ++ 4.9和std=c++11
进行编译。
编辑:
它似乎真的是嵌套模板。我们有两个具有非常深层嵌套模板的测试用例。这些测试的两个.o
文件几乎占最终二进制文件内存的90%。它们导致方法名称长度超过3000个字符。这里没有办法不使用嵌套模板,因为它们构成了一个"处理树"一个示例查询。使用深层嵌套模板时,有没有办法让名字缩短?
答案 0 :(得分:3)
那么有没有办法减少链接期间的RAM使用量?有没有办法在嵌套模板中使用较小的符号?
您是否考虑在客户端代码中使用 pimpl idiom ?
考虑一下你有这个包含链的情况:
A.h - > B.h - > C.h - > D.h(C包括D,B包括C等)
假设A.h定义了AA类,B.h定义了B类等等(AA用BB实现,BB用CC实现等等。)
如果DD是一个大模板并用于CC的实现,模板化代码A,B和C将被编译三次。
现在,考虑如果不是C.h而不是D.h,会发生什么情况,你会遇到以下情况:
C.h foward声明CCImpl *pimpl
并将其所有方法转发给pImpl->
方法(并且不包括D.h)。
C.cpp包括C.h和D.h,并实现CCImpl
和CC
。
现在,D将包含一次(并编译一次,用于C.cpp)。 A和B将仅包括C.h,带有CImpl前向声明。 A.h,B.h和C.h不再知道存在模板。
答案 1 :(得分:2)
GCC对其使用的RAM有一个垃圾收集方案。
参数ggc-min-expand
和ggc-min-heapsize
用于确定GCC何时应该清除并释放未使用的内存(它们的默认值是系统内存总量的百分比)。
您可以尝试以下方式:
g++ --param ggc-min-expand=0 --param ggc-min-heapsize=8192
从GCC手册:
<强> GGC-分钟展开强>
GCC使用垃圾收集器来管理自己的内存分配。此参数指定垃圾的最小百分比 应该允许收集器的堆在集合之间扩展。 调整这可能会提高编译速度;它对代码没有影响 代。
当RAM> = 1GB时,默认值为30%+ 70%*(RAM / 1GB),上限为100%。如果getrlimit可用,那么“RAM”的概念就是 最小的实际RAM,RLIMIT_RSS,RLIMIT_DATA和RLIMIT_AS。如果GCC 无法计算特定平台上的RAM,即下限 使用了30%。将此参数和ggc-min-heapsize设置为零 导致每次机会都发生完整的收集。这是 非常慢,但可以用于调试。
<强> GGC-最小堆大小强>
垃圾收集器堆开始前的最小大小 打扰收集垃圾。第一个集合发生在 堆扩展为ggc-min-expand%超出ggc-min-heapsize。再次,调整 这可能会提高编译速度,并且对代码没有影响 代。 默认值为RAM / 8,下限为4096(4兆字节),上限为131072(128兆字节)。如果getrlimit是 可用,“RAM”的概念是实际RAM中最小的, RLIMIT_RSS,RLIMIT_DATA和RLIMIT_AS。如果GCC无法计算 特定平台上的RAM,使用下限。设置这个 参数非常大,有效地禁用垃圾回收。设置 此参数和ggc-min-expand为零会导致完整集合 发生在每个机会。
进一步详情:
答案 2 :(得分:1)
明智地使用继承。您可能有class Foo<1,4,8,1,9,int, std::string>
作为class Bar
的基类,然后目标文件只会提到Bar
。
请注意,typedef
不会引入用于链接目的的名称。
[编辑] 为了解决另一个注释的性能问题,一个空的派生类在正常的优化级别上不会增加常见编译器的开销(并且即使在调试版本中通常也没有开销)