繁体   English   中英

每个内存位置,堆栈,堆等的目的是什么? (在技术方面失败)

[英]What is the purpose of each of the memory locations, stack, heap, etc? (lost in technicalities)

好吧,我昨天问了Stackoverflow和bufferoverflow之间的区别,几乎被投票遗忘,没有新的信息。

所以它让我思考,我决定重新解释我的问题,希望得到答复,这实际上解决了我的问题。

所以这里什么都没有。

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

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

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

我希望人们在回答这些问题时不要迷失在技术性方面,并且可以让这些术语变得简单,以便外行人理解(即使所描述的概念不是非常流行),并且随着我们的进展继续教育我们技术术语。 我也希望这不是一个太大的问题,因为我认真地认为他们不能单独询问!

什么是堆栈?

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

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

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

当调用第二个函数时,会创建一个新的堆栈帧,将其推送到堆栈的顶部,然后发生调用。 新功能可以很好地消除它的堆栈帧。 当第二个函数返回时,它的堆栈框架被弹出(从堆栈中移除),并且调用者的框架就像以前一样回到原位。

这就是堆栈。 那堆是什么? 它有类似的用途 - 存储数据的地方。 但是,通常需要比单个堆栈帧更长寿的数据。 它不能进入​​堆栈,因为当函数调用返回时,它的堆栈框架被清理并且繁荣 - 那里有你的数据。 所以你把它放在堆上。 堆是一个基本上非结构化的内存块。 你要求x个字节,然后你就可以得到它,然后可以派对它。 在C / C ++中,堆内存保持分配状态,直到您显式解除分配。 在垃圾收集语言(Java / C#/ Python /等)中,当内存上的对象不再使用时,将释放堆内存。

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

堆栈溢出和缓冲区溢出之间有什么不同?

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

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

还记得我提到过返回地址也存储在堆栈中吗? 由于缓冲区溢出,这是许多安全问题的根源。 您的代码使用堆栈上的缓冲区并具有溢出漏洞。 一个聪明的黑客可以构造溢出缓冲区的数据来覆盖该返回地址,指向缓冲区本身的代码,这就是它们如何获得执行代码。 这很讨厌。

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

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

int i;

这保留了(通常)堆栈上的四个字节。 相反,你有:

char * buffer = malloc(100);

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

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

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

char str [128];

例如,它将在堆栈上保留128个字节。 除非你通过调用像malloc这样的分配方法明确地要求它,否则C永远不会到达堆。

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

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

基本上,是的。 操作系统将在进程退出后清理进程使用的内存。 堆是您进程中的一块内存,因此操作系统将清理它。 虽然这取决于你的意思是“清理它”。 操作系统将这些RAM块标记为现在可用,稍后将重复使用。 如果你有明确的清理代码(比如C ++析构函数),你需要确保调用它们,操作系统不会为你调用它们。

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

堆就像它的名字一样,是一堆免费字节,你可以一次抓取一块,做任何你想要的东西,然后扔回去用于别的东西。 你通过调用malloc来获取一大块字节,然后通过调用free来将其丢回。

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

  1. 您不知道在运行时需要多少事情(例如,基于用户输入)。 因此,您可以根据需要在堆上动态分配。

  2. 您需要大型数据结构。 例如,在Windows上,线程的堆栈默认限制为1 meg。 例如,如果您正在处理大型位图,那么这将是一种快速的方法来炸毁堆栈并获得堆栈溢出。 所以你抓住堆的空间,这通常比堆栈大得多。

代码,数据,堆栈和堆?

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

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

那就是概述。 我希望这有帮助。

关于堆栈......这是在存储函数/过程的参数和局部变量的情况下。 更确切地说,当前正在执行的函数的参数和局部变量只能从堆栈中访问...属于在它之前执行的函数链的其他变量将在堆栈中但在当前函数之前不可访问完成了它的运作。

关于全局变量,我相信它们存储在数据段中,并且始终可以从创建的程序中的任何函数访问。

关于Heap ......这些是额外的内存,只要你需要它们就可以分配给你的程序(malloc或new)......你需要知道分配的内存在堆中的位置(地址/指针),这样你就可以了可以在需要时访问它。 如果您丢失了地址,内存将无法访问,但数据仍然存在。 根据平台和语言,这必须由程序手动释放(或发生内存泄漏)或需要进行垃圾回收。 堆栈的堆叠比较大,因此可用于存储大量数据(如文件,流等)...这就是为什么在堆中创建对象/文件以及指向对象/文件的指针存储在堆栈中的原因。

就C / C ++程序而言,数据段存储静态(全局)变量,堆栈存储局部变量,堆存储动态分配的变量(任何mallocnew来获取指针)。 代码段仅存储机器代码(程序中由CPU执行的部分)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM