释放堆栈

时间:2017-12-19 02:26:23

标签: c memory-management

所以我知道在堆栈中分配的变量上调用free()会导致无效的指针错误。

malloc ed指针中,malloc()在实际指针之前分配8个字节,以保留有关其大小的信息。所以我想知道我是否在结构之前创建了long然后在该结构上调用free如果可以释放结构(当然这是假设这8个字节的分配是malloc唯一的额外内容。

我想我的最后一个问题是,如果堆栈变量分配和堆分配之间存在任何真正的区别(就后端对内核的调用而言)。

3 个答案:

答案 0 :(得分:3)

某些C实现可能会在分配的空间之前使用数据来帮助它们管理空间。有些人没有。有些人为某些规模的分配而不是其他分配。如果他们这样做,它可能是八个字节,或者可能是其他一些数量。你不应该依赖这方面的任何行为。

当您在块中声明某个long对象和某种struct时,编译器可能会也可能不会将它们放在堆栈中彼此相邻。它可能会将long放在struct之前,反之亦然,或者,因为它优化了您的程序,它可能会将long保留在寄存器中,而不会将它放在堆栈中,它可能会做其他事情。在一些C实现中,long是八个字节。在某些情况下,事实并非如此。没有好的方法可以确保将两个单独的对象放在相邻的内存中。 (你可以通过将它们放在一个更大的结构中来使它们不分开。)

即使你能够拼凑long后跟struct,你怎么知道要放入long的价值? C实现是否将分配的长度放在那里?或者它是指向另一个块的指针?或者对于数据库的其他部分,C实现用于跟踪分配的内存?如果mallocfree在分配的空间之前使用内存,则该内存不为空。它需要有一些价值,你不知道那是什么。

如果您运气好的话,将struct的地址传递给free可能不会立即导致您的程序崩溃。但是从某种意义上说,你已经释放了一部分堆栈。当您再次调用malloc时,您返回的指针可能是针对该内存的,然后您的程序可能会写入该空间。那么当你的程序调用其他例程会导致堆栈进入那个空间时会发生什么?您将重叠使用相同的内存。你的一些数据会踩踏其他数据,你的程序也无法运行。

是的,堆栈上分配的内存与堆分配的内存之间存在差异。这超出了C为您的程序提供的模型。但是,在进程具有堆栈和堆的系统中,它们通常位于进程内存的不同位置。特别是,当堆栈增长和收缩时,堆栈存储器必须保持可用。你不能在没有破坏的情况下将它与堆混合。

当你尝试各种各样的事情时,询问有关会发生什么的问题是很好的。但是,mallocfree的现代实现非常复杂,您几乎不得不接受它们作为一种您无法轻易查看的服务。相反,为了帮助您学习,您可能会想到这一点:

  • 您如何编写自己的mallocfree

  • 编写一些使用malloc(例如兆字节)分配大量内存的代码,并编写两个名为MyMallocMyFree的例程malloc }和free,除了他们使用你分配的内存。调用MyMalloc时,它会分割出一大块内存。调用MyFree时,它将返回块以使其再次可用。

  • 写一些实验性代码,这些代码随机调用MyMalloc各种大小MyFree,有点随机顺序。

  • 你怎么能完成所有这些工作?你如何将兆字节划分为块?你怎么记得分配了哪些块以及哪些是免费的?当有人打电话给MyFree时,你怎么知道他们回馈了多少钱?当使用MyFree返回相邻的块时,如何将它们重新组合成更大的块?

答案 1 :(得分:0)

我认为你真正的问题是堆栈是如何工作的。

堆栈是程序启动时分配的一个大内存块。有一个指向堆栈顶部的指针。这个名字是暗示性的:想想一堆杂志。

调用函数时,参数将放在堆栈顶部。然后函数本身将其局部变量置于其上。当函数退出时,只需将堆栈指针移回到调用函数之前的位置。这将释放函数使用的所有局部变量和输入参数。

堆管理器与此内存块无关。欺骗free将一些堆栈放入堆管理器的内存中会对您的程序造成严重破坏。当您调用其他函数时,内存可能会再次被使用,如果您malloc内存会同时使用,最好导致数据损坏,最坏情况下会导致堆栈损坏(读取崩溃)。

答案 2 :(得分:0)

当你谈到在堆栈上分配的内存时,你必须明白在大多数实现中,堆栈是在一个块中分配的 - 变量不是单独分配的,也不是单独分配的。

                     +-+ +--------------------------------------------------+
                     |   | Stack frame data section; local variables and    |
                     |   |                                                  |
                     |   | function arguments in order determined by the    |
                     |   |                                                  |
                     |   | calling convention of the target platform        |
Stack frame for      |   |                                                  |
function call;   +---+   | (size is implementation dependent)               |
block allocated      |   |                                                  |
                     |   |                                                  |
                     |   +--------------------------------------------------+
                     |   |Instruction pointer (return address)              |
                     |   +--------------------------------------------------+
                     |   |Space for return value (if not in a CPU register) |
                     +-+ +--------------------------------------------------+
                         |                                                  |
                         |                                                  |
                         |                                                  |
                         |     (stack frame of previously called function)  |
                         |                                                  |
                         |                                                  |
                         +--------------------------------------------------+

每个函数调用都分配有自己的堆栈帧,所需的大小用于保存返回值(如果需要),返回地址的指令指针以及所有局部变量和函数参数。因此,虽然分配了堆栈帧的内存,但它并未针对任何单个变量进行分配 - 仅针对各个大小的总和。