栈:
- 用于静态内存分配(static memory allocation)
- 编译器自动管理,无需手工控制
- 存储在计算机中的RAM(random access memory)
堆:
- 用于动态内存分配(dynamic memory allocation)
- 由我们手工控制,容易memory leak
- 存储在计算机中的RAM(random access memory)
补充:
1.RAM叫做“随机存取存储器”,又做“随机存储器”,是与CPU直接交互数据的内部存储器,也叫主存(内存)。可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。
2.存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。按照存储单元的工作原理,随机存储器又分为静态随机存储器(Static random access memory, SRAM)和静态随机存储器(Dynamic random access memory, DRAM)。
分配在栈中的变量是直接存储到内存,并且获取这个内存也非常快,当程序编译的时候,就会被分配处理。
虽然分配在堆中的变量是在运行时分配内存,并且获取这个内存有点慢,但是堆内存受限于虚拟内存的大小。堆中的元素没有相互依赖,并且总是能够在任何时候随机获取到,这使得它更复杂,因为要跟踪堆的某个部分的内存分配或在某个时候做相应的释放工作。
何时用栈?何时用堆?
如果在编译时之前你知道你有多少数据需要分配并且数据不是太大,那么可以使用栈; 如果你不知道在运行时你需要多少数据或者你需要分配大量数据,你可以使用堆。
在多线程情况下,每个线程都有它自己完全独立的栈,但是它们将共享堆,也正因为不同的线程在一个多线程应用程序(multi-threaded application)中共享堆, 所以这也意味着在这些线程之间会有某些协调,以至于它们不会在同时获取或操作同一个内存块。此外,栈是线程特性(thread specific),而堆是应用特性(application specific)。
对象可以存储在栈中而不是堆中吗?
我们知道,对于变量来说,直接定义的局部变量都是存储在栈中,全局对象或静态对象是放在数据段的静态存储区,用new
来生成的对象都是放在堆中的。但是,对象可以存储在栈中吗?答案是:可以存储在栈中的。如果我们在一个函数里面不使用new
关键字来创建一个对象,那么这个对象是存储在栈中而不是堆中。假如我们有一个 c++类叫做 Dog, 有一个函数叫做 loveDogFunction() :
void loveDogFunction()
{
Dog whiteDog; // 对象whiteDog在函数运行结束时被销毁
}
上面例子,一旦函数完成运行,在栈中被使用在对象 whiteDog
上的内存将被移除或销毁,也可以说是回收。
如果我们想要在函数里面创建一个在堆中的对象,如下:
void loveDogFunction()
{
Dog* blackDog = new Dog();
/**
这个blackDog对象必须被删除,否则会有内存泄漏产生
**/
delete blackDog;
}
在上面的代码中,我们可以看到,blackDog
对象被创建在一个函数中,并且使用了new
关键字,这意味着 blackDog
将被创建在堆中,但是,因为blackDog
是使用new
关键字创建的,所以也意味着我们必须自己删除blackDog
对象,否则就会导致内存泄漏。
内存会在栈中持续多久?在堆中呢?
一旦一个函数调用运行结束,对于该函数,任何已创建在栈中的数据将会自动被删除,任何在堆中的数据将会一直持续直到被程序员手动删除。
栈的大小如何变化?堆呢?
栈会被设置到一个固定尺寸大小,并且不能超过它的固有尺寸(当然,尽管一些语言会有一些扩展来这样做),因此,如果在栈中没有足够的空间来操作这个被分配给它的内存的话,就会产生所谓的栈溢出(stack overflow),这种情况经常会在大量的嵌套函数被调用时发生,或者在那里有着一个无限的递归调用的时候。
如果堆的当前尺寸太小而不能容纳新的内存,那么操作系统就会添加更多的新内存到堆中,这也是堆与栈的比较大的差异之一。
栈和堆怎样实现的?
实现取决于语言、编译器和运行时,对于栈和堆的实现的具体细节总是不同的,这都取决于正在使用的是什么语言,什么编译器。但是,在大的方面,在一种语言中,栈和堆被使用来实现同样的东西,和在另外一种语言中是一样的。
栈和堆那个更快?
显然,栈比堆更快,这是由于在栈中分配内存的方式,在栈中分配内存就像移动栈指针一样简单,使得栈更快。
内存在栈和堆中是怎么释放的?
当变量超过作用域(范围)时,栈中数据被自动释放。然后,在一些语言中,例如C
、C++
,存储在堆中的数据都需要程序员手动删除,删除使用一些特定的关键字如free、delete 或者 delete[]。在另外一些语言,比如Java 或者 中使用垃圾回收来自动删除来自堆中的内存,不需要程序员做任何事情。
欢迎加入 iOS(swift)开发互助群:QQ群号:558179558, 相互讨论和学习!你想要的答案这里或许都有...