C 理解堆栈分配对象的释放
我试图了解堆栈分配对象的释放行为。准确地说,我试图在标准()中找到一个解释。考虑下面的简单函数:C 理解堆栈分配对象的释放,c,arrays,memory-management,C,Arrays,Memory Management,我试图了解堆栈分配对象的释放行为。准确地说,我试图在标准()中找到一个解释。考虑下面的简单函数: void foo(){ char test[4096]; test[10] = 0; } 这里,test数组将在退出foo时解除分配。在objdump中很容易看到test是在堆栈上分配的。标准(重点矿山)规定: 一种对象,其标识符声明时没有链接,也没有 存储类说明符static具有自动存储持续时间 一些复合文字 因此,test具有自动存储持续时间。我们可以很容易地重写函数,如下所示
void foo(){
char test[4096];
test[10] = 0;
}
这里,test
数组将在退出foo
时解除分配。在objdump
中很容易看到test
是在堆栈上分配的。标准(重点矿山)规定:
一种对象,其标识符声明时没有链接,也没有
存储类说明符static具有自动存储持续时间
一些复合文字
因此,test
具有自动存储持续时间。我们可以很容易地重写函数,如下所示:
void test(){
char *test= malloc(4096 * sizeof(char));
test[10] = 0;
free(test);
}
但是我们必须自己解除分配它,而test
仍然具有自动存储持续时间
问题:标准如何规定
字符测试[4096]
将在函数退出时解除分配?标准没有说明测试
是在堆栈上分配的,它是实现定义的。这是关于从分配器函数返回的已分配内存的生存期。对于内存分配器功能,明确规定(引用C11
,第§7.22.3.1章,重点)
[…]
如果分配成功,则返回的指针已适当对齐,以便可以将其分配给
指向具有基本对齐要求的任何类型对象的指针,然后使用
在分配的空间中访问此类对象或此类对象的数组(直到
显式解除分配)。分配对象的生存期从分配开始延长
直到解除分配。[…]
因此,您需要显式地释放分配的内存。除非显式解除分配,否则分配的内存将保持有效以供使用(如果处理不正确,则会导致错误)
OTOH,在第二个代码段中,变量test
仍然超出了函数出口的范围,因为它具有自动存储功能。为变量test
分配的内存(注意:不是test
指向的内存)不再有效,尝试访问将是未定义的行为。请记住,变量test
也是如此,即在函数返回后,&test
变得无效,但是,由于test
指向的内存是通过分配器函数分配的,因此返回该指针并从函数调用中使用它仍然是有效的访问
再次引用规范
[…]如果对象在其外部引用
在生命周期中,行为未定义。[……]
本标准描述了现场的各种存储持续时间 1对象的存储持续时间决定其生存期。那里 有四个存储持续时间:静态、线程、自动和已分配。 7.22.3中描述了分配的存储 2.对象的生存期是程序执行过程中的一部分 保证为其保留的存储空间。存在一个对象, 具有恒定地址,并保留其上次存储的值 在它的一生中。如果在对象的外部引用对象 在生命周期中,行为未定义。指针的值变为 不确定其指向(或刚刚过去)的对象何时到达 生命的尽头 6对于没有可变长度数组类型的对象, 它的生存期从进入它所在的块开始 直到该块的执行以任何方式结束为止。(输入 封闭块或调用函数将挂起,但不会结束, 执行当前块。)如果以递归方式输入块, 每次都会创建对象的新实例。初始值 对象的属性是不确定的。如果为指定了初始化 对象,它在每次声明或复合时执行 在执行块时达到文本;否则,值 每次到达声明时都变得不确定 你说得很对。它本身根本没有描述何时以及如何释放存储。它仅指定何时可以使用定义良好的语义访问该存储。一个实现不需要立即释放具有自动存储持续时间的变量的存储,如果您希望程序符合标准,您就不能触摸它 对于已分配的存储,情况也是如此,但增加了一条警告,即必须明确告知您已完成了对存储的实现。但是,即使您“释放”了它,一个实现也可能会保留它一段时间
纸上可能存在一个非常糟糕的实现,一个永远不会释放内存的实现。但在实践中,这些都是自然淘汰的,因为C的糟糕实现只是被大众废弃,并被抛弃。第一个示例中的
test
变量是一个4096字节的数组。
第二个示例中的test
只是一个指针变量(4/8字节),您可以使用从堆空间malloc(3)
获得的指针值初始化它
test
变量(分别为4096和4/8字节)确实会在程序离开例程时自动释放,但是在第二个示例中,您从堆中额外分配了4096字节,C语言对此一无所知(它们是在没有特殊功能的库例程中分配的,因此,如果不显式地执行此操作,它们不会自动返回到堆。--堆是一个特殊的内存位置,malloc()知道,它允许您以任何顺序获取额外内存,也可以以任何顺序返回。-标准没有规定