堆和栈有什么区别?
栈和堆之间的区别可能会让很多人感到困惑. 因此, 这里有一份有关栈和堆的问题和答案清单, 我认为非常有帮助.
栈和堆存储在哪里?
它们都存储在计算机的 RAM(随机存取存储器)中.
线程如何与栈和堆交互?多线程中栈和堆如何工作?
在多线程应用程序中, 每个线程都有自己的栈. 但是, 所有不同的线程将共享堆. 由于多线程应用程序中的不同线程共享堆, 这也意味着线程之间必须进行某种协调, 以便它们不会同时尝试访问和操作堆中的同一块内存.
对象可以存储在栈上而不是堆上吗?
是的, 对象可以存储在栈中. 如果您在函数内部创建对象而不使用 new
运算符, 那么这将在栈上创建并存储对象, 而不是在堆上. 假设我们有一个名为 Member
的 C++ 类, 我们想为其创建一个对象. 我们还有一个名为 somefunction()
的函数. 代码如下所示:
void somefunction()
{
/* create an object "m" of class Member
this will be put on the stack since the
"new" keyword is not used, and we are
creating the object inside a function
*/
Member m;
} //the object "m" is destroyed once the function ends
因此, 一旦函数运行完成, 或者换句话说, 当它"超出范围"时, 对象 m
就会被销毁. 一旦函数运行完毕, 栈上用于对象 m
的内存将被删除.
如果我们想在函数内部的堆上创建一个对象, 那么代码将是这样的:
void somefunction( )
{
/* create an object "m" of class Member
this will be put on the heap since the
"new" keyword is used, and we are
creating the object inside a function
*/
Member* m = new Member( ) ;
/* the object "m" must be deleted
otherwise a memory leak occurs
*/
delete m;
}
在上面的代码中, 你可以看到对象 m
是在函数内部使用 new
关键字创建的. 这意味着 m
将在堆上创建. 但是, 由于 m
是使用 new
关键字创建的, 这也意味着我们必须自己删除 m
对象——否则我们最终会遇到内存泄漏.
栈上的内存与堆上的内存相比能持续多长时间?
一旦函数调用运行完成, 栈上专门为该函数调用创建的任何数据都将自动被删除. 堆上的任何数据都将保留在那里, 直到程序员手动删除.
栈的大小可以增长吗? 堆的大小可以增长吗?
栈的大小是固定的 , 不能超过固定大小(尽管有些语言有允许这样做的扩展). 因此, 如果栈上没有足够的空间来处理分配给它的内存, 就会发生栈溢出. 这通常发生在调用大量嵌套函数或存在无限递归调用时.
如果当前堆的大小太小, 无法容纳新的内存, 那么操作系统可以向堆中添加更多内存. 这是堆和栈之间的一个很大的区别.
栈和堆是如何实现的?
实现实际上取决于语言、编译器和运行时栈和堆的实现细节总是会有所不同, 具体取决于所使用的语言和编译器. 但从总体上看, 一种语言中的栈和堆用于完成与另一种语言中的栈和堆相同的任务.
哪个更快——栈还是堆?为什么?
栈比堆快得多. 这是因为栈上内存的分配方式. 在栈上分配内存就像将栈指针向上移动一样简单.
如何在栈和堆上释放内存?
当变量超出范围时, 栈上的数据会自动释放. 但是, 在 C 和 C++ 等语言中, 存储在堆上的数据必须由程序员使用内置关键字(如 free
、delete
或 delete[ ]
)手动删除. Java 和 .NET 等其他语言使用垃圾收集自动从堆中删除内存, 而无需程序员执行任何操作.
栈和堆可能出现什么问题?
如果栈内存不足, 则称为栈溢出, 并可能导致程序崩溃. 堆可能存在碎片问题, 当堆上的可用内存被存储为不连续(或断开)的块时会发生这种情况. 因为已使用的内存块位于未使用的内存块之间. 当出现过多碎片时, 分配新内存可能是不可能的. 因为即使有足够的内存用于所需的分配, 但一个大块中可能没有足够的内存用于所需的内存量.
我应该使用哪一个——栈还是堆?
对于编程新手来说, 使用栈可能是一个好主意, 因为它更简单. 由于栈很小, 因此当您确切知道数据需要多少内存, 或者您知道数据的大小非常小时, 您会想要使用它. 当你知道数据需要大量内存, 或者您只是不确定需要多少内存(例如动态数组)时, 最好使用堆.