【问题标题】:How does the JVM spread threads between CPU cores?JVM 如何在 CPU 内核之间传播线程?
【发布时间】:2016-12-30 10:33:01
【问题描述】:

有人可以帮助我了解 JVM 如何在可用的 CPU 内核之间传播线程吗?这是我的愿景,但请纠正我。

所以从一开始:当计算机启动时,引导线程(通常是处理器 0 中核心 0 中的线程 0)开始从地址 0xfffffff0 获取代码。其余所有 CPU/内核都处于称为 Wait-for-SIPI(WFS) 的特殊睡眠状态。

然后在加载操作系统后,它开始管理进程并在 CPU/内核之间调度它们,通过称为 SIPI(启动 IPI)的高级可编程中断控制器 (APIC) 向每个线程发送一个特殊的处理器间中断 (IPI)在 WFS 中。 SIPI 包含该线程应开始获取代码的地址。

例如,操作系统通过在内存中加载 JVM 代码并将 CPU 内核之一指向其地址来启动 JVM(使用上述机制)。之后,作为具有自己的虚拟内存区域的单独 OS 进程执行的 JVM 可以启动多个线程。

所以问题是:如何?

JVM 是否使用与 OS 相同的机制,并且在 OS 给 JVM 的时间片内,是否可以将 SIPI 发送到其他内核并指向应该在单独线程中执行的任务的地址?如果是,那么如何恢复该内核上操作系统可以执行的原始程序?

假设这是不正确的愿景,因为假设涉及其他 CPU/内核的任务应该通过操作系统进行管理。否则,我们可能会中断一些在其他内核上并行运行的操作系统进程的执行。因此,如果 JVM 想要在其他 CPU/内核上启动新线程,它会进行一些操作系统调用并将要执行的任务的地址发送到操作系统。操作系统与其他程序一样调度执行,但不同的是,此执行应该发生在同一个进程中,以便能够访问与其余 JVM 线程相同的地址空间。

它是如何完成的?有人可以详细描述一下吗?

【问题讨论】:

  • JVM是一个普通的进程。它(及其线程)由操作系统/内核管理,包括创建和调度。就像所有其他进程和线程一样。加粗的部分也没有什么特别之处——所有常用线程都是这样工作的。
  • 我们可以从 JVM 中操作哪个 CPU 和内核应该用于某个线程还是完全在操作系统控制之下?
  • 这是特定于平台的。如果您可以编写本机代码,那么在 Linux 中手动调度是通过 sched_setaffinity 系统调用完成的。据我所知,标准库中没有 java 包装器。还可以查看taskset 命令以运行修改后的关联性的整个 JVM。

标签: java multithreading jvm cpu-cores


【解决方案1】:

操作系统默认管理和调度线程。 JVM 对操作系统进行了正确的调用以实现这一点,但并未参与其中。

JVM 是否使用与 OS 相同的机制

JVM 使用操作系统,它不知道实际发生了什么。

每个进程都有自己的虚拟地址空间,同样由操作系统管理。


我有一个库,它使用 JNA 在 Linux 和 Windows 上包装 setaffinity。您需要这样做,因为线程调度是由操作系统而不是 JVM 控制的。

https://github.com/OpenHFT/Java-Thread-Affinity

注意:在大多数情况下,使用亲和力要么 a) 没有帮助,要么 b) 没有你想象的那么大。

我们使用它来减少大约 40 到 100 微秒的抖动,这种情况并不经常发生,但经常足以影响我们的性能。如果您希望您的 99%ile 延迟尽可能低,在微秒范围内,线程亲和性是必不可少的。如果您对 100 个请求中的 1 个多花 1 毫秒感到满意,我不会打扰。

【讨论】:

    猜你喜欢
    • 2020-04-23
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2019-04-08
    • 2018-03-19
    • 1970-01-01
    • 2010-12-31
    • 1970-01-01
    相关资源
    最近更新 更多