2016-04-27 21 views
17

Java应用程序为所有线程启动一个堆。每个线程都有自己的堆栈。Java(JVM)如何为每个线程分配堆栈

当Java应用程序启动时,我们使用JVM选项-Xms-Xmx来控制堆的大小,并使用-Xss来控制堆栈大小。

我的理解是,被创建的堆成为JVM的“托管”内存,并且所有正在创建的对象都被放置在那里。

但是,堆栈创建如何工作? Java是否在创建每个线程时创建一个堆栈?如果是这样,堆栈在内存中的位置?它当然不在“被管理”的堆中。

JVM是从本地内存创建堆栈还是预先为堆栈预分配一部分管理内存区域?如果是这样,JVM如何知道如何创建线程?

+1

您可能会发现[此答案](http://stackoverflow.com/a/25318740/2032064)interresting – Mifeet

回答

4

JVM使用的内存不仅仅是堆。例如Java方法, 线程堆栈和本地句柄被分配在独立于 堆的内存中,以及JVM内部数据结构。

Further reading

因此,要回答你的问题:

不Java中创建为每个线程堆栈被创建的时候吗?

是的。

如果是这样,堆栈在内存中的位置?

在JVM分配的内存中,但不在堆上。

如果是这样,JVM如何知道如何创建线程?

它没有。

您可以创建多达你想,直到你已经刷爆你的JVM内存并获得

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 

编辑:

上述所有指 JVM,但我发现很难相信其他JVM在这些基本问题上会有所不同。

+0

此外,虽然这些都是很好的答案,但这是JVM的内部规范。以上任何情况都可能随时发生变化。它不应该也不重要,因为JVM如何执行其工作。让JVM决定如何最好地管理其资源。 – markspace

+0

是的,但这并不意味着要找出HotSpot如何做并不有趣。 – Mifeet

+0

@markspace谢谢,用特定的'JVM'更新了我的答案,但是你真的认为有'JVM'在这些问题上采取不同的行为吗? – Daniel

30

有关Java specification告诉我们的线程堆栈有几件事情。其中包括:

  • 每个Java虚拟机线程都有一个私有Java虚拟机堆栈,与该线程同时创建。

  • 由于Java虚拟机堆栈从来没有被直接操作,除了推送和弹出帧之外,帧可能是堆分配的。 Java虚拟机堆栈的内存不需要是连续的。

  • 规范允许Java虚拟机堆栈要么具有固定的大小,要么根据计算的需要动态扩展和收缩。

现在,如果我们关注诸如HotSpot等JVM实现,我们可以获得更多信息。以下是我从不同来源收集到的一些事实:

  • HotSpot中线程的最小堆栈大小似乎是固定的。这就是前面提到的-Xss选项。 (Source)

在Java SE 6,在Sparc默认为512K在32位VM,并且在1024K 64位VM。 ...您可以通过使用-Xss选项运行来减少堆栈大小。 ... 64k是每个线程允许的最小堆栈空间量。

  • JRockit从堆栈所在的堆中分配内存。 (Source)

注意,JVM使用更多的内存比刚堆。例如,Java方法,线程堆栈和本地句柄分配在独立于堆的内存中,以及JVM内部数据结构中。

  • 有Java线程和热点区域的原生操作系统线程之间的直接映射。 (Source)

  • 但HotSpot中的Java线程堆栈是软件管理的,它不是OS本地线程堆栈。 (Source)

它使用单独的软件堆栈来传递Java参数,而本地C堆栈用于由虚拟机本身。许多JVM内部变量(如程序计数器或Java线程的堆栈指针)都存储在C变量中,这些变量不保证始终保存在硬件寄存器中。这些软件解释器结构的管理占总执行时间的相当大的份额。

  • JVM还利用用于本机方法和JVM运行时调用(例如类加载)相同的Java线程堆栈。 (Source)。有趣的是,即使分配的对象有时也可能位于堆栈上而不是堆上作为性能优化。(Source)

JVM可以使用一种称为逃逸分析技术,通过它们可以告诉某些对象保持局限于其整个寿命单个线程,而且寿命由给定叠层的寿命为界帧。这些对象可以安全地分配到堆栈而不是堆上。

而且因为图像是胜过千言万语,这里是从James BloomJava memory


一个现在回答大家的一些问题:

如何JVM知道如何可能线程会被创建?

它没有。通过创建可变数量的线程可以很容易地通过矛盾来证明。它确实对线程的最大数量和每个线程的堆栈大小做了一些假设。这就是为什么如果分配过多的线程,你可能会耗尽内存(而不是堆内存!)。

Java是否在创建每个线程时创建一个堆栈?

如前所述,每个Java虚拟机线程都有一个私有Java虚拟机堆栈,与该线程同时创建。(Source)

如果是这样,堆栈在内存中的位置?它当然不在“被管理”的堆中。

如上所述,从技术上讲,Java specification允许堆栈内存存储在堆上。但至少JRockit JVM使用不同的内存部分。

JVM是从本地内存创建堆栈还是预先为堆栈预分配一部分管理内存区域?

栈是JVM管理,因为Java规范prescribes如何必须表现:Java虚拟机堆栈存储帧(§2.6)。 Java虚拟机堆栈类似于传统语言堆栈。用于native方法的本机方法堆栈有一个例外。更多关于这个在the specification

+1

那么,大部分是在[JVM规范](https://docs.oracle.com/javase/specs/jvms/se8/html/)中定义的,不是? AFAIK,GC是从规格中排除的区域。 –

+1

你说得对,JVM规范中比我想象的要多。我在此期间更新了我的答案。 – Mifeet

+0

所以,如果我有一个512MB的堆,如果我创建1000个线程(显然它大于512MB),它占用了我的堆的内存,因此OOM异常或额外的内存空间在操作系统? – Jaskey