使用 static 关键字禁止使用堆栈内存



我必须处理巨大的数组,并且由于某些限制,我无法使用动态内存分配。但是,巨大的数组意味着烧毁堆栈内存。为了避免这种情况,我将我的类对象声明为"静态",希望它们最终出现在 BSS 段中。

这是我的示例模板类:

template<int size1, int size2>
class foo {
public:
unsigned char arr[size1*size2];
int total;
foo();
~foo();
//copy constructor
foo(const foo &bar)
{
for(int i=0; i<size1*size2;++i)
{
arr[i] = bar.arr[i];
}
}
//assignment operator
foo& operator=(const foo& bar)
{
if(this == &bar)
{
return *this; 
}
for(int i=0; i<size1*size2;++i)
{
arr[i] = bar.arr[i];
}
return *this;
}
void newcopy(void *ptr);
};//end of class foo
//Default constructor
template<int size1, int size2>
inline foo<size1, size2>::foo(){
total = size1*size2;
}
//Destructor
template<int size1, int size2>
foo<size1, size2>::~foo()
{
printf("Destructor is being executedn");
}
//Member function
template<int size1, int size2>
inline void foo<size1, size2>::newcopy(void *ptr)
{
unsigned char *local = (unsigned char *)ptr;
for(int i=0; i<size1*size2;++i)
{
arr[i] = (unsigned char)(local[i]);
}
}

这是我的示例主函数:

#define val1 2500
#define val2 3000
int main(int argc, char **argv)
{
static foo<val1,val2> bar1;
static foo<val1,val2> bar2;
static foo<val1,val2> temp;
/*  bar1 = fill_data<val1, val2>(128);
bar2 = fill_data<val1, val2>(255);  */
//filling data into objects
for(int i =0; i<val1*val2;++i)
{
bar1.arr[i] = 128;
bar2.arr[i] = 255;
}
//simple swap
temp.newcopy(bar1.arr);
bar1.newcopy(bar2.arr);
bar2.newcopy(temp.arr);
//printing a few values after swap
for(int i =0; i<10;++i)
{
printf("%d %dn", bar1.arr[i], bar2.arr[i]);
}
return 0;
}

正如预期的那样,声明为静态的对象显示在 BSS 段中。

输出带有静态关键字的代码的"size"命令:

text  data  bss      dec
2801  640  22500112 22503249

输出不带静态关键字的代码的"size"命令:

text  data  bss      dec
2366  640   8        2998

如果我执行此操作,程序运行正常。

现在,我为数据填充部分创建了一个单独的函数,将其移出main,如下所示:

template<int size1, int size2>
foo<size1, size2> fill_data(int thresh){
foo<size1, size2> in;
for(int i =0; i<size1*size2;++i)
{
in.arr[i] = thresh;
}
return in;
}

当我调用这个函数时(请参阅主函数中的注释块),我得到了一个分段错误。(如果 val1 和 val2 组合值不超过 5000,我不会得到段错误)

当我调试它时,它甚至没有进入 main!

段错误是因为堆栈溢出吗?

但是,在我在此代码中看到的内容中,既没有大变量,也没有深度函数调用,也没有任何递归来炸毁堆栈。

我在这里错过了什么吗?有人可以详细解释我这个段错误的原因吗?

我使用 RHEL6 64 位。

你避免任何堆分配(newmalloc、mmap(2))是错误的,你应该解释为什么你需要这样做(考虑也许有自己的分配器)。大多数C++容器都在使用一些,并使用RAII管理其内部存储器(标准容器,例如std::vector,接受一些分配器模板参数)。阅读有关C++五法则的信息。考虑使用智能指针。所以arr应该是一些指针字段(也许是一个聪明的),而不是一个巨大的数组字段。

如果你的代码是针对某个嵌入式设备,它需要大量的内存,你应该考虑实现你自己的mallocfree(或找到一些合适的实现),newdelete可以使用。

但是您的fill_data返回了一个巨大的数据结构(超过 2500*3000 字节)。如果您研究 x86-64 ABI,您会发现它在堆栈上使用临时内存区域(嵌入式处理器的 ABI 可能也是如此)。对于庞大的数据结构,你吹掉了调用堆栈,你会得到一个堆栈溢出(这是一个分段错误)。

根据经验,您的调用堆栈被限制为几兆字节(参见setrlimit(2)...),在嵌入式系统上通常更少。有一些方法可以增加这个限制(在Linux上,但可能不是在你的嵌入式系统上)。小心多线程应用程序。

最新更新