Java(JVM)如何为每个线程分配堆栈

Kev*_*vin 46 java memory jvm

Java应用程序启动时,所有线程都有一个堆.每个线程都有自己的堆栈.

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

我的理解是,正在创建的堆成为JVM的"托管"内存,所有正在创建的对象都放在那里.

但堆栈创建如何工作?Java是否在创建每个线程时为其创建堆栈?如果是这样,堆栈在内存上的确切位置?它肯定不在"托管"堆中.

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

Mif*_*eet 65

Java规范告诉我们有关于线程堆栈的一些事情.除其他事项外:

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

  • 由于除了推送和弹出帧之外,永远不会直接操作Java虚拟机堆栈,因此可以对堆进行堆分配.Java虚拟机堆栈的内存不需要是连续的.

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

现在,如果我们专注于像HotSpot这样的JVM实现,我们可以获得更多信息.以下是我从不同来源收集的一些事实:

  • HotSpot中线程的最小堆栈大小似乎是固定的.这就是上述-Xss选项的用途. (资源)

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

  • JRockit分配与堆栈所在的堆分开的内存.(资源)

请注意,JVM使用的内存多于堆.例如,Java方法,线程堆栈和本机句柄分配在与堆不同的内存中,以及JVM内部数据结构中.

  • Java线程与HotSpot中的本机OS线程之间存在直接映射.(来源).

  • 但HotSpot中的Java线程堆栈是软件管理的,它不是OS本机线程堆栈.(资源)

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

  • JVM还为本机方法和JVM运行时调用(例如类加载)使用相同的Java线程堆栈.(来源).

  • 有趣的是,即使分配的对象有时可能位于堆栈上而不是堆上,作为性能优化.(资源)

JVM可以使用一种称为转义分析的技术,通过该技术,它们可以判断某些对象在其整个生命周期内仍然局限于单个线程,并且该生命周期受给定堆栈帧的生命周期的限制.可以在堆栈而不是堆上安全地分配这些对象.

而且因为一张图片胜过千言万语,这里有一张来自詹姆斯布鲁姆的照片 Java内存


现在回答你的一些问题:

JVM如何知道如何创建线程?

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

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

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

如果是这样,堆栈在内存上的确切位置?它肯定不在"托管"堆中.

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

JVM是否从本机内存创建堆栈,还是为堆栈预先分配了一部分托管内存区域?

堆栈是JVM管理的,因为Java规范规定了它必须如何表现:Java虚拟机堆栈存储帧(第2.6节).Java虚拟机堆栈类似于传统语言的堆栈.一个例外是用于native方法的Native Method堆栈.在规范中再次提到这一点.

  • 好吧,其中大多数是在[JVM规范](https://docs.oracle.com/javase/specs/jvms/se8/html/)中定义的,不是吗?AFAIK,GC是规范中未包括的区域。 (2认同)
  • 那么,如果我有一个 512MB 的堆,并且如果我创建 1000 个线程(显然它大于 512MB),它是否会占用我的堆内存,从而导致 OOM 异常或操作系统中的额外内存空间? (2认同)

Dan*_*iel 6

JVM使用的内存多于堆.例如,Java方法,线程堆栈和本机句柄分配在与堆不同的内存中,以及JVM内部数据结构中.

进一步阅读.

那么回答你的问题:

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

是.

如果是这样,堆栈在内存上的确切位置?

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

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

它没有.

您可以创建任意数量的内容,直到最大化JVM内存并获得

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
Run Code Online (Sandbox Code Playgroud)

编辑:

以上所有内容都指的是Jrockit JVM,虽然我发现很难相信其他JVM在这些基本问题上会有所不同.