有人可以帮我理解JVM如何在可用的CPU内核之间传播线程吗?这是我的愿景,它是如何工作的,但请纠正我。
所以从一开始:当计算机启动时,引导线程(通常是处理器0中核心0中的线程0)开始从地址0xfffffff0中获取代码。所有其余的CPU /内核都处于特殊的睡眠状态,称为Wait-for-SIPI(WFS)。
然后在加载OS之后,它开始管理进程并在CPU /内核之间调度它们,通过高级可编程中断控制器(APIC)发送特殊的处理器间中断(IPI),称为SIPI(启动IPI)到WFS中的每个线程。 SIPI包含该线程应从其开始获取代码的地址。
因此,例如,OS通过在内存中加载JVM代码并将其中一个CPU内核指向其地址(使用上述机制)来启动JVM。之后,作为具有自己的虚拟内存区域的单独OS进程执行的JVM可以启动多个线程。
所以问题是:如何?
JVM是否使用与OS相同的机制,并且在操作系统提供给JVM的时间片中,可以将SIPI发送到其他核心并指向应在单独线程中执行的任务的地址?如果是,那么如何恢复操作系统可以在此核心上执行的原始程序?
假设视觉不正确,假设涉及其他CPU /核心的任务应该通过OS进行管理。过度我们可以中断在其他核心上并行运行的某些OS进程的执行。因此,如果JVM想要在其他CPU /核心上启动新线程,则会进行一些OS调用并将要执行的任务的地址发送到OS。 OS计划执行与其他程序一样,但不同的是,此执行应在同一进程中发生,以便能够访问与其余JVM线程相同的地址空间。
怎么做?有人可以更详细地描述一下吗?
JVM是一个普通的过程。 它(及其线程)由OS /内核管理,包括创建和调度。 就像所有其他进程和线程一样。 你用粗体添加的部分也没什么特别的 - 这就是所有常用线程的工作方式。
我们可以从JVM操作CPU和核心应该用于某个线程还是完全受OS控制?
这是特定于平台的。 如果您可以编写本机代码,那么在Linux中,手动调度由sched_setaffinity系统调用完成。 据我所知,标准库中没有java包装器。 另请参阅taskset命令以运行具有已修改关联的整个JVM。
操作系统默认管理和调度线程。 JVM对操作系统进行正确调用以实现此目的,但不会涉及到。
Does JVM use the same mechanism as OS
JVM使用操作系统,它不知道实际发生了什么。
每个进程都有自己的虚拟地址空间,同样由操作系统管理。
我有一个库,它使用JNA在Linux和Windows上包装setaffinity。 您需要这样做,因为线程调度由OS而不是JVM控制。
https://github.com/OpenHFT/Java-Thread-Affinity
注意:在大多数情况下,使用亲和力a)没有帮助,或b)没有你想象的那么多。
我们使用它来减少大约40-100微秒的抖动,这种情况不会经常发生,但通常足以影响我们的性能。 如果您希望99%的ile延迟尽可能低,则在微秒范围内,线程亲和力至关重要。 如果100个请求中的1个可以延长1毫秒,我就不会打扰了。