问题描述
编程语言书籍中经常解释值类型被创建在栈上,引用类型被创建在堆上,但是并没有本质上解释这堆和栈是什么。我仅有高级语言编程经验,没有看过对此更清晰的解释。我的意思是我理解什么是栈,但是它们到底是什么,在哪儿呢(站在实际的计算机物理内存的角度上看)?
1.在通常情况下由操作系统(OS)和语言的运行时(runtime)控制吗?
2.它们的作用范围是什么?
3.它们的大小由什么决定?
4.哪个更快?
答案一
栈是为执行线程留出的内存空间。当函数被调用的时候,栈顶为局部变量和一些 bookkeeping 数据预留块。当函数执行完毕,块就没有用了,可能在下次的函数调用的时候再被使用。栈通常用后进先出(LIFO)的方式预留空间;因此最近的保留块(reserved block)通常最先被释放。这么做可以使跟踪堆栈变的简单;从栈中释放块(free block)只不过是指针的偏移而已。
堆(heap)是为动态分配预留的内存空间。和栈不一样,从堆上分配和重新分配块没有固定模式;你可以在任何时候分配和释放它。这样使得跟踪哪部分堆已经被分配和被释放变的异常复杂;有许多定制的堆分配策略用来为不同的使用模式下调整堆的性能。
每一个线程都有一个栈,但是每一个应用程序通常都只有一个堆(尽管为不同类型分配内存使用多个堆的情况也是有的)。
直接回答你的问题: 1. 当线程创建的时候,操作系统(OS)为每一个系统级(system-level)的线程分配栈。通常情况下,操作系统通过调用语言的运行时(runtime)去为应用程序分配堆。 2. 栈附属于线程,因此当线程结束时栈被回收。堆通常通过运行时在应用程序启动时被分配,当应用程序(进程)退出时被回收。 3. 当线程被创建的时候,设置栈的大小。在应用程序启动的时候,设置堆的大小,但是可以在需要的时候扩展(分配器向操作系统申请更多的内存)。 4. 栈比堆要快,因为它存取模式使它可以轻松的分配和重新分配内存(指针/整型只是进行简单的递增或者递减运算),然而堆在分配和释放的时候有更多的复杂的 bookkeeping 参与。另外,在栈上的每个字节频繁的被复用也就意味着它可能映射到处理器缓存中,所以很快(译者注:局部性原理)。
答案二
Stack:
1.和堆一样存储在计算机 RAM 中。
2.在栈上创建变量的时候会扩展,并且会自动回收。
3.相比堆而言在栈上分配要快的多。
4.用数据结构中的栈实现。
5.存储局部数据,返回地址,用做参数传递。
6.当用栈过多时可导致栈溢出(无穷次(大量的)的递归调用,或者大量的内存分配)。
7.在栈上的数据可以直接访问(不是非要使用指针访问)。
8.如果你在编译之前精确的知道你需要分配数据的大小并且不是太大的时候,可以使用栈。
9.当你程序启动时决定栈的容量上限。
Heap:
1.和栈一样存储在计算机RAM。
2.在堆上的变量必须要手动释放,不存在作用域的问题。数据可用 delete, delete[] 或者 free 来释放。
3.相比在栈上分配内存要慢。
4.通过程序按需分配。
5.大量的分配和释放可造成内存碎片。
6.在 C++ 中,在堆上创建数的据使用指针访问,用 new 或者 malloc 分配内存。
7.如果申请的缓冲区过大的话,可能申请失败。
8.在运行期间你不知道会需要多大的数据或者你需要分配大量的内存的时候,建议你使用堆。
9.可能造成内存泄露。
举例:
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;
答案三
堆和栈是两种内存分配的两个统称。可能有很多种不同的实现方式,但是实现要符合几个基本的概念:
1.对栈而言,栈中的新加数据项放在其他数据的顶部,移除时你也只能移除最顶部的数据(不能越位获取)。 |
|