我正在从事一个物联网项目,其中内存管理很重要。
我遇到了堆栈使用问题:如果直接将返回结构的函数(或语句表达式或Lambda)作为另一个函数的参数调用,则会在堆栈上添加新结构,并且不会重用内存。
下面的示例代码在堆栈中添加了4种结构
struct TestStruct
{
uint32_t field1;
uint32_t field2;
uint32_t field3;
uint32_t field4;
} ;
struct TestStruct initStructure(uint32_t f1, uint32_t f2, uint32_t f3, uint32_t f4)
{
struct TestStruct myStruct;
myStruct.field1 = f1;
myStruct.field2 = f2;
myStruct.field3 = f3;
myStruct.field4 = f4;
return myStruct;
}
void doStuff(struct TestStruct myStruct)
{
printf("f1 = %d, f2 = %d, f3 = %d, f4 = %d", myStruct.field1, myStruct.field2, myStruct.field3, myStruct.field4);
}
int main(void)
{
doStuff(initStructure(1,2,3,4));
doStuff(initStructure(11,22,33,44));
doStuff(initStructure(11,12,13,14));
doStuff(initStructure(21,22,23,24));
}
我会认为,由于结构的行为就像在单独范围内的自动临时变量一样,因此内存将被重用。在每个函数调用周围添加作用域不会执行任何操作,因此在您输入主函数时,结构会保留在堆栈中。
我正在使用ARM GCC,并且-fstack-reuse = all和-Os,-Og,-O1,-O2会发生这种情况。有没有办法强迫这些变量重用堆栈?
谢谢
更新:碰巧的是,我们的工作环境已设置为无论如何都使用-x c++
,这是导致堆栈问题的原因。看来c ++ 14和c ++ 17在堆栈重用方面并不是很积极,这对我们来说是个问题。
另一点是,上面的代码的行为确实与我在环境中所解释的相同,但不是在干净的环境中。要观察堆栈问题,可以initStructure
函数进行如下修改:
struct TestStruct initStructure(uint32_t f1, uint32_t f2, uint32_t f3, uint32_t f4)
{
struct TestStruct myStruct;
myStruct.field1 = f1;
myStruct.field2 = f2;
myStruct.field3 = f3;
myStruct.field4 = f4;
printf("Temporary address %x", &myStruct);
return myStruct;
}
在没有-x c++
的情况下,堆栈可以重用,但是堆栈没有被重用。
为什么c ++无法重用堆栈?我们在编译时使用了一些非常有趣的字符串计算,这在C语言中是不可用的,因此对我们而言,同时进行字符串处理和内存优化非常重要。
答案 0 :(得分:1)
也许您的代码应该看起来像这样。通过指针传递结构,这样,您无需将所有结构都复制到堆栈中,而仅将其地址复制到堆栈中。就您而言,当您调用doStuff(initStructure(1,2,3,4))
时,堆栈中同时具有3个复制的结构。
函数initStructure()
在堆栈中为2个结构保留了内存,因为您将其返回类型声明为结构,并且在函数内部创建了另一个局部结构。函数doStuff
在堆栈中为您传递给它的参数分配1个结构。由于不需要通过调用函数在堆栈上分配那么多的内存,因此按指针传递在性能上也将是最佳的。
typedef struct
{
uint32_t field1;
uint32_t field2;
uint32_t field3;
uint32_t field4;
}TestStruct;
TestStruct myStruct;
void initStructure(uint32_t f1, uint32_t f2, uint32_t f3, uint32_t f4, TestStruct* myStruct)
{
//struct TestStruct myStruct;
myStruct->field1 = f1;
myStruct->field2 = f2;
myStruct->field3 = f3;
myStruct->field4 = f4;
//return &myStruct;
}
void doStuff(TestStruct* myStruct)
{
printf("f1 = %d, f2 = %d, f3 = %d, f4 = %d", myStruct->field1, myStruct->field2, myStruct->field3, myStruct->field4);
}
int main(void)
{
initStructure(1,2,3,6,&myStruct);
doStuff(&myStruct);
}