编程语言书籍解释说,值类型是在栈上创建的,而引用类型是在堆上创建的,但没有解释这两个东西是什么。我还没有读过这方面的明确解释。 我明白什么是堆栈。但是。
堆栈:
堆:
delete
、delete[]
或free
来释放数据。new
或malloc
分配。例子:
int foo()
{
char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
bool b = true; // Allocated on the stack.
if(b)
{
//Create 500 bytes on the stack
char buffer[500];
//Create 500 bytes on the heap
pBuffer = new char[500];
}//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;
堆栈 当你调用一个函数时,该函数的参数和其他一些开销被放在堆栈中。一些信息(如返回时的位置)也被存储在那里。 当你在函数中声明一个变量时,该变量也被分配到堆栈中。
解除堆栈的分配是非常简单的,因为你总是以分配的相反顺序解除分配。堆栈的东西在你进入函数时被添加,相应的数据在你退出函数时被删除。这意味着你倾向于呆在堆栈的一个小区域内,除非你调用大量的函数,而这些函数又调用大量的其他函数(或创建一个递归的解决方案)。
堆 堆是一个通用的名字,指的是你把你在运行中创建的数据放在哪里。如果你不知道你的程序要创建多少艘飞船,你可能会使用new(或malloc或类似的)操作符来创建每艘飞船。这种分配要坚持一段时间,所以我们很可能会以不同于我们创建的顺序释放东西。
因此,堆的情况要复杂得多,因为最终会有一些未使用的内存区域与一些有使用的块交错在一起--内存被分割开了。找到你需要的空闲内存是一个困难的问题。这就是为什么应该避免使用堆的原因(尽管它仍然经常被使用)。
实施 栈和堆的实现通常是由运行时/操作系统决定的。通常,游戏和其他对性能要求很高的应用程序会创建自己的内存解决方案,从堆中抓取一大块内存,然后在内部分配,以避免依赖操作系统的内存。
这只有在你的内存使用情况与正常情况完全不同的情况下才实用--例如在游戏中,你在一个巨大的操作中加载一个关卡,并可以在另一个巨大的操作中把整个关卡扔掉。
内存中的物理位置 这比你想象的要少,因为有一种叫做虚拟内存的技术,它使你的程序认为你可以访问某个地址,而物理数据在其他地方(甚至在硬盘上!)。当你的调用树越来越深时,你得到的堆栈地址是按顺序递增的。堆的地址是不可预测的(即特定的植入),坦率地说并不重要。
堆栈是内存的一部分,可以通过几个关键的汇编语言指令进行操作,如'pop'(从堆栈中删除和返回一个值)和'push'(将一个值推到堆栈中),也可以调用(调用一个子程序--这将地址推到堆栈中返回)和返回(从子程序中返回--这将地址从堆栈中弹出并跳到它)。 它是堆栈指针寄存器下面的内存区域,可以根据需要进行设置。 堆栈也用于向子程序传递参数,也用于在调用子程序之前保存寄存器中的值。
堆是操作系统给应用程序的一部分内存,通常通过malloc这样的系统调用。 在现代操作系统中,这部分内存是一组只有调用进程才能访问的页面。
堆栈的大小是在运行时决定的,在程序启动后一般不会增长。 在C语言程序中,堆栈需要大到足以容纳每个函数中声明的每个变量。 堆会根据需要动态增长,但操作系统最终会进行调用(它通常会使堆的增长超过malloc请求的值,这样至少未来的一些malloc就不需要再回到内核去获得更多内存。 这种行为通常是可定制的)
因为你在启动程序之前已经分配了堆栈,所以你在使用堆栈之前从来不需要malloc,所以这也是一个小小的优势。 在实践中,很难预测在有虚拟内存子系统的现代操作系统中什么会快,什么会慢,因为如何实现页面以及它们的存储位置是一个实现细节。