为什么这段 Java 代码没有利用所有 CPU 核心?
当使用正确的参数启动时,附加的简单 Java 代码应该加载所有可用的 cpu 核心。例如,你以
java VMTest 8 int 0
它将启动 8 个线程,这些线程除了循环并将 2 加到整数上之外什么也不做。在寄存器中运行的东西甚至不分配新的内存。
我们现在面临的问题是,当运行这个简单的程序(当然有 24 个线程)时,我们没有加载 24 核机器(AMD 2 个插槽,每个插槽 12 个核)。类似的情况也会发生在 2 个程序(每个程序有 12 个线程)或更小的机器上。
因此我们怀疑 JVM(Linux x64 上的 Sun JDK 6u20)无法很好地扩展。
有没有人看到类似的东西或者有能力运行它并报告它是否在他/她的机器上运行良好(请仅>= 8核)?有想法吗?
我也在 8 核的 Amazon EC2 上尝试过,但虚拟机的运行似乎与真实机器不同,因此加载行为完全奇怪。
package com.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class VMTest
{
public class IntTask implements Runnable
{
@Override
public void run()
{
int i = 0;
while (true)
{
i = i + 2;
}
}
}
public class StringTask implements Runnable
{
@Override
public void run()
{
int i = 0;
String s;
while (true)
{
i++;
s = "s" + Integer.valueOf(i);
}
}
}
public class ArrayTask implements Runnable
{
private final int size;
public ArrayTask(int size)
{
this.size = size;
}
@Override
public void run()
{
int i = 0;
String[] s;
while (true)
{
i++;
s = new String[size];
}
}
}
public void doIt(String[] args) throws InterruptedException
{
final String command = args[1].trim();
ExecutorService executor = Executors.newFixedThreadPool(Integer.valueOf(args[0]));
for (int i = 0; i < Integer.valueOf(args[0]); i++)
{
Runnable runnable = null;
if (command.equalsIgnoreCase("int"))
{
runnable = new IntTask();
}
else if (command.equalsIgnoreCase("string"))
{
runnable = new StringTask();
}
Future<?> submit = executor.submit(runnable);
}
executor.awaitTermination(1, TimeUnit.HOURS);
}
public static void main(String[] args) throws InterruptedException
{
if (args.length < 3)
{
System.err.println("Usage: VMTest threadCount taskDef size");
System.err.println("threadCount: Number 1..n");
System.err.println("taskDef: int string array");
System.err.println("size: size of memory allocation for array, ");
System.exit(-1);
}
new VMTest().doIt(args);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我没有看到你的代码有什么问题。
然而,遗憾的是,您无法在 Java 中指定处理器关联性。因此,这实际上是由操作系统决定的,而不是 JVM。这完全取决于操作系统如何处理线程。
您可以将 Java 线程拆分为单独的进程,并将它们包装在本机代码中,以便为每个核心放置一个进程。当然,这确实会使通信变得复杂,因为它将是进程间通信而不是线程间通信。不管怎样,这就是像 boink 这样流行的网格计算应用程序的工作原理。
否则,您将受到操作系统的支配来安排线程。
I don't see anything wrong with your code.
However, unfortunately, you can't specify the processor affinity in Java. So, this is actually left up to the OS, not the JVM. It's all about how your OS handles threads.
You could split your Java threads into separate processes and wrap them up in native code, to put one process per core. This does, of course, complicate communication, as it will be inter-process rather than inter-thread. Anyway, this is how popular grid computing applications like boink work.
Otherwise, you're at the mercy of the OS to schedule the threads.
我猜这是 JVM/OS 固有的,而不一定是您的代码。检查 Sun 的各种 JVM 性能调整文档,例如 http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf 建议使用
numactl
在 Linux 上设置亲和力。祝你好运!
I would guess this is inherent to the JVM/OS and not necessarily your code. Check the various JVM performance tuning docs from Sun, e.g. http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf which suggests using
numactl
on Linux to set the affinity.Good luck!
显然,您的虚拟机正在所谓的“客户端”模式下运行,其中所有 Java 线程都映射到一个本机操作系统线程,因此由一个 CPU 核心运行。尝试使用
-server
开关调用 JVM,这应该可以解决问题。如果您收到:
错误:找不到“服务器”JVM
,则必须从 JDK 的jre\bin
复制server
目录JRE 的bin
目录。Apparently your VM is running in so-called "client" mode, where all Java threads are mapped to one native OS thread and consequently are run by one single CPU core. Try to invoke the JVM with
-server
switch, this should correct the problem.If you get an:
Error: no 'server' JVM
found, you'll have to copy theserver
directory from a JDK'sjre\bin
directory to JRE'sbin
.uname -a
2.6.18-194.11.4.el5 #1 SMP 9 月 21 日星期二 05:04:09 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
Intel(R) Xeon(R) CPU E5530 @ 2.40GHz
http://browse.geekbench.ca/geekbench2/view/182101
Java 1.6.0_20 -b02
16cores,程序消耗了 100% cpu,如 vmstat 所示
有趣的是,我写这篇文章是因为我怀疑我的应用程序没有利用所有内核,因为 cpu 利用率从未增加,但响应时间开始恶化
uname -a
2.6.18-194.11.4.el5 #1 SMP Tue Sep 21 05:04:09 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
Intel(R) Xeon(R) CPU E5530 @ 2.40GHz
http://browse.geekbench.ca/geekbench2/view/182101
Java 1.6.0_20-b02
16cores, the program consumed 100% cpu as shown by vmstat
Interestingly I came to this article because I am suspecting my application is not utilizing all the cores as the cpu utilisation never increases but the response time starts deteriorating
我注意到即使在 C 语言中,紧循环也经常会出现这样的问题。根据操作系统的不同,您还会看到相当大的差异。
根据您使用的报告工具,它可能不会报告某些核心服务使用的 CPU。
Java 往往非常友好。您可以在 Linux 中尝试相同的操作,但将进程优先级设置为某个负数,然后看看它的行为如何。
如果您的 jvm 不使用绿色线程,那么在应用程序内设置线程优先级也可能会有所帮助。
很多变数。
I've noticed even on C that a tight loop often has issues like that. You'll also see pretty vast differences depending on OS.
Depending on the reporting tool you are using, it may not report the CPU used by some core services.
Java tends to be pretty friendly. You might try the same thing in linux but set the process priority to some negative number and see how it acts.
Setting thread priorities inside the app may help a little too if your jvm isn't using green threads.
Lots of variables.