以下程序将调用乐趣 2 ^(MAXD + 1)次。尽管(如果我的想法是正确的话),最大递归深度不应该超过MAXD。因此编译可能需要一些时间,但它不应该吃我的RAM。为什么这个constexpr代码会导致GCC吃掉我所有的RAM?
#include<iostream>
const int MAXD = 20;
constexpr int fun(int x, int depth=0){
return depth == MAXD ? x : fun(fun(x + 1, depth + 1) + 1, depth + 1);
}
int main(){
constexpr int i = fun(1);
std::cout << i << std::endl;
}
问题是,吃我的RAM正是它所做的。当MAXD高达30时,我的笔记本电脑在GCC 4.7.2快速分配3GB左右后开始交换。我还没有尝试过与叮当3.1,因为我现在无法访问它。
我唯一的猜测是,这与GCC试图过于聪明并且记忆函数调用有关,就像模板一样。如果是这样的话,他们没有限制他们做多少记忆,例如MRU高速缓存表的大小或什么的没有限制吗?我还没有找到一个开关来禁用它。
为什么要这样做? 我喜欢制作高级编译时间库的想法,比如遗传编程或其他东西。由于编译器没有编译时间尾部调用优化,所以我担心任何循环都需要递归,并且(即使我调出最大递归深度参数,这似乎有点难以要求)会快速分配所有的RAM并填充它与毫无意义的堆栈帧。因此,我提出了上述解决方案,可以在没有深度堆栈的情况下获取任意多个函数调用。这种功能可以用于折叠/循环或蹦床。
编辑: 现在我已经在3.1版中尝试过了,不管我多长时间工作(即MAXD有多高),它都不会泄漏内存。与预期的一样,CPU使用率几乎为100%,内存使用率几乎为0%。也许这只是GCC中的一个bug。
我已确认堆栈永远不会超越MAXD(如预期的那样),通过运行函数运行时并观察到,尽管我可以使其运行很长时间,但它根本不使用RAM。 – Gurgeh
可能您应该按照http://gcc.gnu.org/bugs/中的建议报告此问题吗? – osgx
@osgx这不是一个真正的bug,不过,是吗?根据标准,我想他们可以对我的RAM做他们喜欢的事情。另外,我希望有人知道他们在做什么(你知道你是谁),告诉我是什么原因。 – Gurgeh