释放堆栈

问题描述 投票:0回答:3

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

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

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

c memory-management
3个回答
3
投票

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

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

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

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

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

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

  • 你会怎么写自己的mallocfree
  • 写一些使用malloc分配大量内存的代码,比如一兆字节,然后编写两个名为MyMallocMyFree的例程,它们的工作方式类似于mallocfree,除了它们使用你分配的内存。当调用MyMalloc时,它将分割出一大块内存。当调用MyFree时,它将返回块以使其再次可用。
  • 写一些实验代码,有点随机调用各种大小的MyMallocMyFree
  • 你怎么能让所有这些工作?你如何将兆字节划分为块?你怎么记得分配了哪些块以及哪些是免费的?当有人打电话给MyFree时,你怎么知道他们回馈了多少?当相邻的块与MyFree一起返回时,你如何将它们重新组合成更大的碎片?

0
投票

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

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

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

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


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)  |
                         |                                                  |
                         |                                                  |
                         +--------------------------------------------------+

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

© www.soinside.com 2019 - 2024. All rights reserved.