如果我理解正确,堆栈用于本地素数和对堆中对象的引用。那么如果你有多个线程会发生什么呢?
它们是否同时共享相同的堆栈空间(但不同的区域),或者 JRE 在线程之间切换时是否切换上下文并加载-卸载堆栈内容?
或者 JRE 是否为每个线程分配单独的堆栈?
如果我理解正确,堆栈用于本地素数和对堆中对象的引用。那么如果你有多个线程会发生什么呢?
它们是否同时共享相同的堆栈空间(但不同的区域),或者 JRE 在线程之间切换时是否切换上下文并加载-卸载堆栈内容?
或者 JRE 是否为每个线程分配单独的堆栈?
或者 JRE 是否为每个线程分配单独的堆栈?
概念上是的。(例如,请参阅此JVM 规范链接。)
规范的概念化如何在特定的 JVM 中实现是特定于实现的。但是,我的理解是,当前一代(例如 Hotspot)JVM 将每个线程堆栈分配到操作系统请求的单独内存块中。例如使用mmap
系统调用1。
当发生线程切换时,肯定不会大规模复制堆栈内容。然而,线程上下文切换确实需要保存和加载寄存器,并且(间接地)额外加载内存缓存和 TLB 条目。这可能很重要……这就是为什么过多的线程上下文切换(例如,由锁争用或过多的等待/通知引起的)可能对性能不利。
1 - 我记得有些 JVM 在每个堆栈段的末尾包含一个只读的“红色区域”页面。(这意味着线程堆栈溢出会触发内存故障,并且 JVM 不需要在每个方法调用上显式检查堆栈溢出,这将严重影响性能。)无论如何,我的理解是“红色区域” " 页面要求使用 mmap 请求线程堆栈。
每个线程都有自己的堆栈,该堆栈为在该线程上执行的每个方法保存一个框架,如您在“每个线程”部分中所见。
或者 JRE 是否为每个线程分配单独的堆栈?
是的。JVM 被指定这样做:
每个 Java 虚拟机线程都有一个私有的Java 虚拟机堆栈,与线程同时创建。Java 虚拟机堆栈存储帧。[...] 因为除了推送和弹出帧外,Java 虚拟机堆栈永远不会被直接操作,因此帧可能是堆分配的。
Java 线程由线程对象表示,每个线程都分配有一个单独的线程堆栈,用于存储运行时数据。线程堆栈具有特定大小(可以使用 VM 选项设置java -Xss1m Application
)。
如果在运行时,线程尝试存储超过堆栈大小允许的日期,则会发生堆栈溢出错误。