为什么Java使用堆来分配内存?
我刚刚在一本java书中读到这样的说法,说java中的对象驻留在堆上。 使用堆是否是因为它是存储数据和快速检索数据的最佳方式?
作为一个初学者,我对数据结构只有一个想法。我的意思是为什么不堆叠或其他东西?
I just read this statement in a java book saying Objects in java reside on a heap.
Is a heap used because it is the best way to store data and retrieve data fast ?
I only have an idea about data structures being a beginner. I mean why not stack or something else ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
堆栈的问题在于您只能删除最近添加的内容。这对于局部变量来说效果很好,因为它们随着您进入和退出函数而变化,但对于生命周期不遵循单个函数的任意数据来说则不太好。内存堆允许你随意添加和删除数据。
The problem with a stack is that you can only remove the most recent thing you added. This works fine for local variables, since they come and go as you enter and exit functions, but not so well for arbitrary data who's lifecycle doesn't follow that of individual functions. The memory heap allows you to add and remove data at will.
堆仅由虚拟机用来分配和释放内存块。要访问那里的对象,您可以使用对内存块的引用(该引用位于堆栈中)。 jvm 不允许直接访问内存(就像在 C/C++ 中一样)。
The heap is used just by the vm to allocate and deallocate blocks of memory. To access the objects there you use a reference to the block of memory (that reference is in the stack). The jvm doesn't allow direct access to the memory (like in C/C++).
它是底层计算模型的产物。对于操作系统来说,内存看起来像是一个大的、大部分连续的空间,可以通过地址在其中读取和写入数据。操作系统允许进程获取一块内存(一个大的连续空间,通常至少是几K的一页),并通过使用内存地址和读/写操作来随意处理。
java堆建立在它的基础上,即对于程序员来说,它看起来就像一大堆内存(当然不是,即垃圾收集通常会移动东西),他获得“地址”(实际上是引用,它们实际上不是)地址)用于写入此内存空间的数据(对象)。这使您可以最大程度地灵活地在此基础上构建更专业的数据结构。
请记住,对于程序员来说,它就像一个“堆”,因为这为您提供了必要的灵活性,但不必如此实现。它是由垃圾收集器管理的一块内存,它使用一堆数据结构来完成其工作,您可以将其视为堆的一部分,也可以不将其视为堆的一部分,即它是由 JVM 使用和分配的内存,但通常在这种情况下,只有程序员可以访问的内存才被视为“堆”。
It's an artifact of the underlying computing model. Memory to the operating system looks like a big, mostly contiguous space in which data can be read and written by address. The operating system allows processes to grab a block of memory (a large contiguous space, usually at least one page of a couple K) and to do with that as they like, by using memory addresses and read/write operations.
The java heap builds on that, i.e. to the programmer it just looks like a big bag of memory (it of course is not, i.e. garbage collection routinely moves stuff around) to which he gets "addresses" (references really, they are not actually addresses) for data (objects) written to this memory space. This allows you maximum flexibility to build more specialised data structures on top of that.
Remember that it acts like a "heap" to the programmer, because that allows you the necessary flexibility, but it doesn't have to be implemented as such. It's a piece of memory managed by the garbage collector, and there are a bunch of data structures it uses to do its job, which you could or could not consider part of the heap, i.e. it's memory used and allocated by the JVM, but usually only the memory accessible to the programmer is considered to be "the heap" in this context.
为什么不在栈上存储对象呢?那么,当前正在执行的方法停止执行后,堆栈会发生什么情况呢?
Why not store objects on the stack? Well, what happens to the stack after the currently executing method stops executing?
因为 Java 中的对象通常比创建它们的作用域还要长,此时为该作用域创建的堆栈帧将不再存在。
相反,当创建对象的范围不再存在时,分配的堆空间不会自动释放。
Because objects in Java often outlive the scope within which they were created, at which point the stack frame that was created for the scope ceases to exist.
Allocated heap space on the contrary is not deallocated automatically when the scope within which the object was created no longer exist.
因为Java使用垃圾收集器来回收内存,这与C和C++不同。在这些语言中,将堆栈用于局部变量*是有意义的。在 Java 中,不存在(本地)变量超出范围的概念,只是不再引用它,这使得它有资格进行垃圾回收(这肯定会在该点之后的某个时候发生) 。
* 为清楚起见,这并不意味着 C/C++ 中没有堆,或者不能使用
malloc
/new< /code> 系列分配仅在本地范围内使用的变量。
Because Java uses a garbage collector to reclaim memory, unlike C and C++. In those languages it makes sense to use the stack for local variables*. In Java, there is no concept of a (local) variable going out of scope, only it is not referenced anymore, which makes it eligible for garbage collection (which is bound to happen sometime after that point).
* which, for the sake of clarity, does not mean that there were no heap in C/C++, or that you could not use the
malloc
/new
family to allocate variables to be used solely within local scope.Java 可以在堆栈上存储对象,前提是它进行了逃逸分析,确定方法返回时非本地对象不会保留对该对象的引用。它不允许您声明对象存储在堆栈中。
如果 Java 确实允许对象显式地位于堆栈上,那么当方法返回时会发生什么?由任何非本地对象持有的对本地对象的任何引用会发生什么?
Java 设计者可能已经确定某些引用可能无效,如果取消引用,则会导致未定义的行为。就像C/C++中的指针一样。 Java 设计者似乎竭尽全力避免未定义的行为。
Java 设计者可以指定对本地对象的所有引用都变为空。找到所有这些参考资料会很困难。并且会导致很难发现由于假设不为空的引用突然变为空而引起的错误。包含对象引用的不可变对象是不可能的。将引用设置为 null 的通知机制必须跨线程工作。所有这些的成本将远远高于本地存储的优势。
语言设计者之一 James Gosling 拥有 Lisp 背景,这种影响体现在以下想法中:对象处置仅留给垃圾收集器,编译器或运行时环境会优化对象处置(逃逸分析),如果 )
Java can store objects on the stack, if it does escape analysis that determines that no references to the object are retained by non local objects when the method returns. It does not allow you to declare that an object is stored on the stack.
If Java did allow objects to be explicitly on the stack, what would happen when the method returned? What would happen to any references to the local object, held by any non local objects?
The Java designers could have decided that some references could be invalid, leading to undefined behaviour if dereferenced. Just like a pointer in C/C++. The Java designers seem to have gone to great lengths to avoid undefined behaviour.
The Java designers could have specified that all references to the local object became null. Finding all those references would be difficult. And it would result in difficult to find bugs caused by references that were assumed to be not null suddenly became null. Immutable objects containing object references would be impossible. And the notification mechanism that set references to null would have to work across threads. The cost of all this would be much higher than the advantage of local storage.
One of language designers, James Gosling, has a Lisp background, and that influence is visible in the idea that object disposal is just left to the garbage collector, with the compiler or run time environment optimising object disposal (escape analysis) if possible.