gpt4 book ai didi

memory - 每个内存位置、堆栈、堆等的目的是什么? (迷失在技术细节上)

转载 作者:行者123 更新时间:2023-12-02 18:58:22 25 4
gpt4 key购买 nike

好的,我昨天问了 Stackoverflow 和 bufferoverflow 之间的区别,几乎被否决了,没有新信息。

所以这让我开始思考,我决定重新表述我的问题,希望我能得到真正解决我问题的答复。

所以这里什么也没有。

我知道四个内存段(如果我错了,请纠正我)。代码、数据、堆栈和堆。现在AFAIK代码段存储代码,而数据段存储与程序相关的数据。真正让我困惑的是堆栈和堆的用途!

据我了解,当您运行一个函数时,该函数的所有相关数据都存储在堆栈中,并且当您在函数内部递归调用函数时,在函数内部......当函数正在等待输出时在前一个函数中,函数及其必需的数据不会从堆栈中弹出。所以你最终会出现堆栈溢出。 (如果我错了,请再次纠正我)

我也知道堆是干什么用的。正如我在某处读到的那样,它用于在程序执行时动态分配数据。但这提出了更多解决我的问题的问题。当我最初在代码中初始化我的变量时会发生什么。它们是在代码段中,还是在数据段中,还是在堆中?数组存储在哪里?是不是在我的代码执行完后堆中的所有内容都被删除了?总而言之,请以更简单的方式告诉我堆,而不仅仅是 malloc 和 alloc,因为我不确定我是否完全理解这些术语是什么!

我希望人们在回答时不要迷失在技术细节中,并且可以使术语保持简单,让外行人理解(即使要描述的概念不是外行人),并在我们进行过程中继续用技术术语来教育我们。我也希望这不是一个太大的问题,因为我真的认为它们不能分开问!

最佳答案

堆栈是干什么用的?

每个程序都由函数/子例程/任何您选择的语言调用它们组成。几乎总是,这些函数有一些本地状态。即使在一个简单的 for 循环中,您也需要某个地方来跟踪循环计数器,对吗?那必须存储在内存中的某个地方。

关于函数的事情是他们几乎总是做的另一件事是调用其他函数。那些其他函数有它们自己的局部状态——它们的局部变量。您不希望本地变量干扰调用者中的本地变量。另一件必须发生的事情是,当 FunctionA 调用 FunctionB 然后必须做其他事情时,您希望 FunctionA 中的局部变量仍然存在,并且在 FunctionB 完成时具有相同的值。

跟踪这些局部变量就是堆栈的用途。每个函数调用都是通过设置所谓的堆栈帧来完成的。堆栈帧通常包括调用者的返回地址(当函数完成时)、任何方法参数的值以及任何局部变量的存储。

当调用第二个函数时,会创建一个新的堆栈帧,将其压入堆栈顶部,然后调用发生。新函数可以愉快地处理其堆栈框架。当第二个函数返回时,它的堆栈帧被弹出(从堆栈中移除)并且调用者的帧像以前一样回到原位。

这就是堆栈。那么堆是什么?它有一个类似的用途——一个存储数据的地方。但是,通常需要比单个堆栈帧生命周期更长的数据。它不能进入​​堆栈,因为当函数调用返回时,它的堆栈帧会被清理和爆炸——你的数据就在那里。所以你把它放在堆上。堆基本上是一个非结构化的内存块。你要求 x 字节数,你得到它,然后就可以聚会了。在 C/C++ 中,堆内存保持分配状态,直到您明确取消分配。在垃圾收集语言(Java/C#/Python/etc.)中,当不再使用堆上的对象时,堆内存将被释放。

从上面解决您的具体问题:

堆栈溢出和缓冲区溢出有什么区别?

它们都是超出内存限制的情况。堆栈溢出是特定于堆栈的;您已经编写了代码(递归是一个常见的,但不是唯一的原因),因此它有太多的嵌套函数调用,或者您在堆栈上存储了很多大的东西,并且空间不足。大多数操作系统都对堆栈可以达到的最大大小设置了限制,当您达到该限制时,您会遇到堆栈溢出。现代硬件可以检测堆栈溢出,这对您的进程来说通常是厄运。

缓冲区溢出有点不同。所以第一个问题 - 什么是缓冲区?嗯,这是一块有界的内存。该内存可能在堆上,也可能在堆栈上。但重要的是你有 X 字节,你知道你可以访问。然后编写一些代码,将 X + 更多字节写入该空间。编译器可能已经将缓冲区之外的空间用于其他事情,并且由于写入过多,您已经覆盖了其他事情。缓冲区溢出通常不会立即被看到,因为在您尝试对其他已被丢弃的内存执行某些操作之前您不会注意到它们。

另外,还记得我是如何提到返回地址也存储在堆栈中的吗?由于缓冲区溢出,这是许多安全问题的根源。您的代码使用堆栈上的缓冲区并存在溢出漏洞。聪明的黑客可以构造溢出缓冲区的数据以覆盖该返回地址,指向缓冲区本身中的代码,这就是他们获取代码执行的方式。真恶心。

当我最初在代码中初始化我的变量时会发生什么。它们是在代码段中,还是在数据段中,还是在堆中?

我将在这里从 C/C++ 的角度谈一谈。假设你有一个变量声明:

国际我;

这在堆栈上保留(通常)四个字节。如果你有:

char *buffer = malloc(100);

这实际上保留了两块内存。对 malloc 的调用在堆上分配了 100 个字节。但是您还需要存储指针,缓冲区。该存储再次位于堆栈上,并且在 32 位机器上将是 4 个字节(64 位机器将使用 8 个字节)。

数组存储在哪里......?

这取决于您如何声明它们。如果你做一个简单的数组:

字符 str[128];

例如,这将在堆栈上保留 128 个字节。 C 永远不会命中堆,除非您通过调用 malloc 之类的分配方法明确要求它。

相反,如果您声明一个指针(如上面的缓冲区),则该指针的存储在堆栈上,数组的实际数据在堆上。

是不是在我的代码执行完后,堆中的所有内容都被删除了......???

基本上,是的。操作系统会在进程退出后清理进程使用的内存。堆是进程中的一块内存,因此操作系统将对其进行清理。尽管这取决于您所说的“清理”是什么意思。操作系统将这些 RAM 块标记为现在空闲,稍后将重用它。如果您有明确的清理代码(如 C++ 析构函数),您需要确保它们被调用,操作系统不会为您调用它们。

总而言之,请以更简单的方式告诉我堆,而不仅仅是 malloc 和 alloc?

堆,就像它的名字一样,是一堆空闲字节,你可以一次抓取一块,做任何你想做的事情,然后扔回去用于其他东西。您可以通过调用 malloc 获取一大块字节,然后通过调用 free 将其扔回去。

你为什么要这样做?嗯,有几个常见的原因:

  • 你不知道有多少东西
    你需要直到运行时间(基于
    例如用户输入)。那么你
    在堆上动态分配为
    你需要他们。
  • 您需要大型数据结构。在
    以 Windows 为例,一个线程的
    堆栈默认限制为 1
    梅格。如果您正在与大型
    位图,例如,这将是一个
    快速提升筹码并获得
    堆栈溢出。所以你捕获那个
    堆的空间,通常是
    比堆栈大得多。

  • 代码、数据、堆栈和堆?

    不是一个真正的问题,但我想澄清一下。 “代码”段包含应用程序的可执行字节。通常,代码段在内存中是只读的,以帮助防止篡改。数据段包含编译到代码中的常量 - 代码中的字符串或数组初始值设定项之类的东西需要存储在某个地方,数据段就是它们去的地方。同样,数据段通常是只读的。

    堆栈是内存的可写部分,通常大小有限。操作系统将初始化堆栈,C 启动代码会为您调用 main() 函数。堆也是内存的可写部分。它由操作系统保留,并且诸如 malloc 和 free 之类的功能可以管理从中取出块并将它们放回原处。

    所以,这就是概述。我希望这有帮助。

    关于memory - 每个内存位置、堆栈、堆等的目的是什么? (迷失在技术细节上),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3921182/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com