2010-05-07 25 views
11

我刚刚在一本java书中读到这个声明,说java中的Objects驻留在堆上。 是否使用了堆,因为它是快速存储数据和检索数据的最佳方式?为什么Java使用堆进行内存分配?

我只对数据结构是初学者有一个想法。我的意思是为什么不堆叠或其他东西?

+13

如果你正在阅读一本关于数据结构的书,那么请注意,在计算机科学中,“heap”有两个*常见的含义。一个是树状数据结构,另一个是内存分配的一般空间。 Java的堆是内存分配的一般空间。 – 2010-05-07 09:56:22

+2

我也一直在想这件事。这很有趣,因为在我的第一个单身汉中,术语栈堆栈仅用于编程环境。那时我对数据结构一无所知。现在我已经研究了数据结构,我可以理解为什么堆栈是堆栈,但不是为什么堆是堆。我可以在已经研究过数据结构的人的答案中看到,而谁没有:)。其实,格雷格上面的评论回答了最好的恕我直言的问题。正如我读到的:'堆'不一定是'堆'。 http://en.wikipedia.org/wiki/Heap – 2010-09-06 11:46:12

回答

13

堆栈的问题是,您只能删除最近添加的东西。这适用于局部变量,因为它们在进入和退出函数时来来去去,但对于生命周期并不遵循单个函数的任意数据而言并不那么好。内存堆允许您随意添加和删除数据。

+0

这个答案在某种程度上非常棒,因为它解释了为什么堆有时比堆栈更好,使得它听起来好像堆也需要成为堆数据结构,从字面上看。这也是非常混乱,以同样的方式。 – unwind 2010-05-07 09:59:43

+0

@unwind:答案非常简单,没有什么让人困惑的。你觉得哪些部分令人困惑? – instantsetsuna 2010-08-18 09:03:59

1

由于Java使用垃圾回收器来回收内存,与C和C++不同。在这些语言中,将堆栈用于局部变量*是有意义的。在Java中,没有一个(局部)变量超出范围的概念,只有它不再被引用,这使得它有资格进行垃圾回收(在这一点之后,必然会发生)。

*为清晰起见,并不意味着有在C/C++没有堆,或者说你不能使用malloc/new家庭分配变量仅局部范围内使用。

+0

C和C++也使用堆。它通过malloc/free(C和C++)或new/delete(仅限C++)访问。 OP没有询问局部变量,BTW。 – 2010-05-07 09:54:06

+0

@Marcelo坎托斯,当然。我的回答如何表明相反?咄。 – 2010-05-07 09:55:56

+0

我在发表评论后编辑了答案。另外,您修改后的回复仍然不合格。 OP想知道为什么要把对象放在堆上(“为什么不是堆栈?”)。你的回答是,“因为Java使用垃圾收集器......”,这显然是错误的。 – 2010-05-07 10:11:55

1

为什么不将对象存储在堆栈上?那么,当前正在执行的方法停止执行后,堆栈会发生什么?

3

堆仅用于vm来分配和释放内存块。要访问对象,可以使用对内存块的引用(该引用位于堆栈中)。 jvm不允许直接访问内存(就像在C/C++中一样)。

1

由于Java中的对象经常超出它们的创建范围,此时为该范围创建的堆栈框架不复存在。

相反的分配的堆空间不会在创建对象的范围不存在时自动解除分配。

2

这是底层计算模型的工件。内存到操作系统看起来像一个很大的,大多数连续的空间,在这个空间里数据可以通过地址读写。操作系统允许进程通过使用内存地址和读/写操作来获取一块内存(一个大的连续空间,通常至少有一对K的页面),并按照他们的喜好进行操作。这个Java堆是建立在它上面的,也就是说对于程序员来说,它看起来像一大堆内存(当然不是,即垃圾回收通常会将东西移动到其他地方)它们实际上不是地址)写入该内存空间的数据(对象)。这使您可以最大限度地灵活地在其上构建更专用的数据结构。

请记住,它对程序员来说就像一个“堆”,因为它可以让你有必要的灵活性,但它不必像这样实施。它是由垃圾收集器管理的一块内存,它有一堆数据结构用来完成它的工作,你可以或不可以考虑堆的一部分,也就是说它是由JVM使用和分配的内存,但通常只有程序员可以访问的内存被认为是这个上下文中的“堆”。

0

Java可以将对象存储在堆栈上,如果存在的话转义分析确定在方法返回时,非本地对象不保留对对象的引用。它不允许你声明一个对象存储在堆栈上。

如果Java确实允许对象显式地位于堆栈上,那么当方法返回时会发生什么?由任何非本地对象持有的对本地对象的任何引用会发生什么?

  • Java的设计者可能决定一些参考可能是无效,导致不确定的行为,如果取消引用。就像在C/C++中的指针一样。 Java设计师似乎已经竭尽全力避免未定义的行为。

  • Java设计者可能已经指定对本地对象的所有引用都变为null。找到所有这些参考文献将是困难的。这会导致很难找到由假定不为null的引用引起的错误突然变为空。包含对象引用的不可变对象是不可能的。并且将引用设置为null的通知机制必须跨线程工作。所有这些的成本将远高于本地存储的优势。

  • James Gosling是语言设计师之一,拥有Lisp背景,并且这种影响可以通过编译器或运行时环境优化对象处置(转义分析) 如果可能的话。