欺骗JVM关于可用核心数量的信息(在Linux上)

13

有些情况下需要让JVM认为它运行在具有N个核心的机器上,而不是实际的核心数量(例如,4个核心而不是16个)。

JVM在基于Mandriva/Red Hat Linux内核的某些Linux构建下运行。

这个问题是一个边界问题,因为我期望有各种解决此问题的方法。这不是纯粹的Linux管理问题,也不是纯粹的程序员问题。

那么...有什么想法吗?


man cpuset 应该会有帮助。 - Joachim Isaksson
@JoachimIsaksson 如果您能提供一些运行java jar的实时示例,那将非常好且有帮助。 - Andremoniy
1
JVM应该只被调度到4个核心吗?还是JVM应该认为只有4个核心,从而仅启动4个线程进行并行执行?这必须是进程特定的设置,还是(临时的)系统范围内更改也可以? - nosid
@nosid JVM 应该只考虑和看到 4 个核心,而不是它们实际的数量。 - Andremoniy
1
如果在Mandriva上可用cgroups,请使用它。使用cgroups,您可以为每个进程组分配资源。在您的情况下,您只想将4个CPU分配给JVM。这是一个关于cgroups的维基百科http://en.wikipedia.org/wiki/Cgroups - alvits
2个回答

11

为了让Runtime.getRuntime().availableProcessors()返回您想要的内容,您可以使用LD_PRELOAD技巧覆盖JVM_ActiveProcessorCount函数。以下是一个小程序来实现这一点:

#include <stdlib.h>
#include <unistd.h>

int JVM_ActiveProcessorCount(void) {
    char* val = getenv("_NUM_CPUS");
    return val != NULL ? atoi(val) : sysconf(_SC_NPROCESSORS_ONLN);
}

首先,制作一个共享库:

gcc -O3 -fPIC -shared -Wl,-soname,libnumcpus.so -o libnumcpus.so numcpus.c

然后按以下方式运行Java:

$ LD_PRELOAD=/path/to/libnumcpus.so _NUM_CPUS=2 java AvailableProcessors

请注意,JVM也使用sysconf()来计算编译器和GC线程的数量。但是,您可以使用-XX:CICompilerCount=n -XX:ConcGCThreads=m -XX:ParallelGCThreads=m显式地设置JVM线程的数量。 - apangin
在Java 9中,它实际上会检查Linux上的cpuset。 - eckes
同时,@apangin 指向了 JDK-8u-121 来解决这个问题。 - Kedar Mhaswade

6
下面的Java程序将打印Java VM看到的处理器数量:
public class AvailableProcessors {
    public static void main(String... args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

如果我在家里的电脑上执行这个程序,它会打印出4,这是实际的处理器数量(包括超线程)。现在让我们欺骗Java虚拟机,让它认为只有两个处理器:

$ echo '0-1' > /tmp/online
$ mount --bind /tmp/online /sys/devices/system/cpu/online

如果我再次运行上面的程序,它会打印2而不是4
这个技巧会影响到系统上的所有进程。然而,可以将其限制为仅影响特定的进程。Linux 上的每个进程都可以有自己的挂载点命名空间。例如,在mount(2)的手册页中查看预处理命名空间部分。您可以使用lxc来启动具有其自己的挂载命名空间的新进程。

好的,这是一项困难的黑客技术。好的,就这样吧 :) - Andremoniy
我发现这是一个更好的解决方案: https://www.cyberciti.biz/faq/debian-rhel-centos-redhat-suse-hotplug-cpu/ - Medvednic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接