为什么内存分配需要栈和堆
我已经搜索了一段时间,但没有关于为什么值类型必须分配在堆栈上而引用类型(即动态内存或对象必须驻留在堆上)的结论性答案。 为什么不能在堆栈上分配相同的值?
I've searched a while but no conclusive answer is present on why value types have to be allotted on the stack while the reference types i.e. dynamic memory or the objects have to reside on the heap.
why cannot the same be alloted on the stack?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
他们可以。实际上,它们并非如此,因为堆栈通常是比堆更稀缺的资源,并且在堆栈上分配引用类型可能会很快耗尽它。此外,如果函数返回在其堆栈上分配的数据,则需要在调用者方面复制语义,否则可能会面临返回将被下一个函数调用覆盖的内容的风险。
值类型(通常是局部变量)可以使用本机机器指令快速轻松地带入和带出范围。返回值类型的复制语义很简单,因为大多数都适合机器寄存器。这种情况经常发生,并且应该尽可能便宜。
They can be. In practice they're not because stack is a typically scarcer resource than heap and allocating reference types on the stack may exhaust it quickly. Further, if a function returns data allocated on its stack, it will require copying semantics on the caller's part or risk returning something that will be overwritten by the next function call.
Value types, typically local variables, can be brought in and out of scope quickly and easily with native machine instructions. Copy semantics for value types on return is trivial as most fit into machine registers. This happens often and should be as cheap as possible.
值类型总是存在于堆栈中是不正确的。阅读 Jon Skeet 关于该主题的文章:
It is not correct that value types always live on the stack. Read Jon Skeet's article on the topic:
我知道堆栈范例(嵌套分配/解除分配)无法处理某些需要非嵌套对象生命周期的算法。
正如静态分配范式无法处理递归过程调用一样。 (例如斐波那契(n)的简单计算为f(n-1)+ f(n-2))
我不知道有一个简单的算法可以说明这个事实。任何建议将不胜感激:-)
I understand that the stack paradigm (nested allocations/deallocations) cannot handle certain algorithms which need non-nested object lifetimes.
just as the static allocation paradigm cannot handle recursive procedure calls. (e.g. naive calculation of fibonacci(n) as f(n-1) + f(n-2))
I'm not aware of a simple algorithm that would illustrate this fact though. any suggestions would be appreciated :-)
局部变量在栈中分配。如果不是这种情况,则在分配变量内存时将无法让变量指向堆。如果需要,您可以在堆栈中分配内容,只需在本地创建一个足够大的缓冲区并自行管理即可。
Local variables are allocated in the stack. If that was not the case, you wouldn't be able to have variables pointing to the heap when allocating variable's memory. You CAN allocate things in the stack if you want, just create a buffer big enough locally and manage it yourself.
当方法退出时,方法放入堆栈的任何内容都会消失。在 .net 和 Java 中,如果类对象在对它的最后一个引用消失后就消失,那是完全可以接受的(实际上是可取的),但如果对象在对它的引用仍然存在的情况下消失,那将是致命的。在一般情况下,编译器不可能知道,当方法创建对象时,对该对象的任何引用在方法退出后是否会继续存在。如果没有这样的保证,分配类对象的唯一安全方法是将它们存储在堆上。
顺便说一句,在 .net 中,可变值类型的一个主要优点是它们可以通过引用传递,而无需放弃对它们的永久控制。如果类“foo”或其方法具有结构“boz”,foo 的方法之一通过引用方法“bar”来传递该结构,则 bar 或其调用的方法可以执行它们想做的任何操作“ boz' 直到他们返回,但是一旦 'bar' 返回,它对 'boz' 的任何引用都将消失。与用于类对象的混杂共享引用相比,这通常会带来更安全、更清晰的语义。
Anything a method puts on the stack will vanish when the method exits. In .net and Java, it would be perfectly acceptable (in fact desirable) if a class object vanished as soon as the last reference to it vanished, but it would be fatal for an object to vanish while references to it still exist. It is not in the general case possible for the compiler to know, when a method creates an object, whether any references to that object will continue to exist after the method exits. Absent such assurance, the only safe way to allocate class objects is to store them on the heap.
Incidentally, in .net, one major advantage of mutable value types is that they can be passed by reference without surrendering perpetual control over them. If class 'foo', or a method thereof, has a structure 'boz' which one of foo's methods passes by reference to method 'bar', it is possible for bar, or the methods it calls, to do whatever they want to 'boz' until they return, but once 'bar' returns any references it held to 'boz' will be gone. This often leads to much safer and cleaner semantics than the promiscuously-sharable references used for class objects.