【问题标题】:Constant CPU load in JavaJava 中的恒定 CPU 负载
【发布时间】:2015-04-23 13:31:43
【问题描述】:

如何使 CPU 利用率更稳定?

我想用 java 生成一个人工负载,它会强调 CPU 并消耗 RAM。资源消耗保持恒定很重要。此处的重点是 CPU。 RAM 是次要的。我选择 Java 是因为它几乎可以在所有平台上运行。我很想看看我的计算机上的这种负载是否会持续消耗每小时 20% 的 CPU 利用率,但在我的第二台计算机上可能是 30%。为了实现更高的 CPU 利用率和多核压力,程序使用多线程运行。

我已经阅读了 generate CPU load in JavaArtificial generation of cpu load in Java 在 stackoverflow 上的提问。

这是我的代码。我有一个类来控制线程和一个类来提供负载的线程。我选择计算阶乘来强调 CPU。

package loadPackage;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class LoadController {

    public static void main(String[] args) {
        int threads = 16;
        int runlength = 100000;
        long time;
        try {
            runlength = Integer.parseInt(args[0]);
        } catch (Exception e) {
            System.out.println("Only integer allowed!");
        }
        time = System.currentTimeMillis() + runlength;
        ExecutorService executor = Executors.newFixedThreadPool(threads);
        for (int i = 0; i < threads; i++) {
            Runnable worker = new Workload(time);
            executor.execute(worker);
          }
        executor.shutdown();
        while (!executor.isTerminated()) {
        }

    }

}



package loadPackage;

import java.math.BigInteger;

public class Workload implements Runnable  {
    private long time;

    public Workload(long time) {
        this.time = time;
    }

    public void run() {
        while (System.currentTimeMillis() < time) {
            BigInteger fact = BigInteger.valueOf(1);
            for (int i = 1; i <= 6000; i++) {
                fact = fact.multiply(BigInteger.valueOf(i));
            }
            try {
                Thread.sleep(200);
            }
            catch (Exception localException1) {}
        }
    }

}

我的测量工具每 5 分钟测量一次(不是样本,而是此期间的平均利用率)。因此可以容忍最小的变化。但是,有时它会显示出我无法解释的强烈峰值。

问题一:您知道为什么我的 CPU 利用率会出现如此强烈的峰值吗?

问题二: 我可以使用哪些编程技术来最小化 CPU 利用率偏差?


[2015 年 4 月 30 日更新]

我假设质疑一个原因:超线程
我有一台带超线程的 HP 笔记本电脑 i7 四核(任务管理器显示 8 个虚拟内核)。我使用的测量工具具有超线程校正并显示实际消耗的资源。然而,这是一个猜测,VisualVM 只测量虚拟内核消耗!?我试图在 BIOS 中停用超线程以证明我的假设的正确性。但感谢 HP,此选项在 BIOS 中的配置下不可用。您认为,超线程是导致测量偏差的原因吗?

替代方法:不同的 JVM
我正在使用标准 JVM“Java HotSpot(TM) 64-Bit Server VM”。使用更紧凑的 JVM 是否有助于更稳定的 Java 资源消耗?

【问题讨论】:

  • 不确定这样的程序是否可行。即使你设法写了一个,你如何确保其他外部因素保持不变?您如何确保操作系统不消耗任何 CPU 周期?您如何计算分析器消耗的 CPU 周期?
  • 您使用的是什么版本的 Java?
  • @bot 我打印出每个线程的 while 循环每次迭代的毫秒数。大多数情况下,执行时间仅相差 1-3 毫秒。然后那里有一些小的巨大的跳跃。我试图以更高的优先级运行线程,但仍然如此。我玩弄了睡眠时间和阶乘的参数,以便 cpu 利用率不会太高,操作系统仍然可以获得资源。但我不知道峰值是来自 java 本身还是另一个进程“窃取”了 cpu 时间。我有一个 i7,有四个核心,总​​共 8 个虚拟。
  • @SleimanJneidi 我正在使用 Java 6.0.240.7

标签: java load cpu-usage


【解决方案1】:

CPU 利用率由操作系统管理,因此 AFAIK 无法将 Java 线程“锁定”到特定处理器(这将导致持续利用率)。 当您在 linux 系统上打开 htop 时,您会看到这一点。线程会像蟋蟀一样在你的 CPU 上跳跃。 我从来没有设法在java 中实现这种持续使用,只有在C(++) 中。

【讨论】:

  • 所以你说关键是切换到C++?是因为 Java JVM 以及解释器和 C++ 正在编译吗?如果我切换到 C++,在那里实现这种持续利用的关键是什么? C++ 提供了哪些 Java 没有的功能?
  • 好吧,在 C 语言中,您基本上可以编写更接近底层硬件的代码。在 Java 中,您仍然有额外的解释器。另外,我还没有在 Java 中看到使我能够在那个核心上运行这个线程的方法。因为您的操作系统的调度程序正在做出该决定。也许您应该寻找不同的JVM?有好几个。
【解决方案2】:

我建议您在此过程中启动视觉虚拟机。您将能够跟踪 GC 活动。如果您看到 GC 峰值消耗的 CPU 时间与您之前看到的一样,那么您可以确定这就是原因。

【讨论】:

  • 嗨,Steph,我用 VisualVM 分析了我的程序。感谢您的建议。奇怪的是,我用其他工具测量的那些峰值在 VisualVM 中不可见。我还使用了 Tracer 插件。使用 Tracer,我的负载似乎相当稳定。有时 GC 会启动并导致小峰。但这是可以忍受的。我的猜测是,我使用的原始测量工具中的强峰值的解释来自超线程。
  • 这很有趣。很难很快下结论,这就是为什么使用一些工具更容易消除一些疑虑。
  • 我更新了我上面的问题并添加了超线程的可能根本原因。你知道一个考虑到 HT 并且易于使用的 java 配置文件吗? VisualVM 可能只显示虚拟 CPU 消耗,还是我错了?
  • 不,我没有。我会尝试禁用超线程并再次测试,但我读到你已经这样做了
【解决方案3】:

我知道这个线程有点老了,但是如果您仍然感兴趣,请查看https://github.com/OpenHFT/Java-Thread-Affinity 上的 OpenHFT Java 线程关联库。我已经使用它来将 Java 线程固定到给定的内核并为某些应用程序产生良好的性能(CPU 使用率)。

正如作者的博客 (http://vanillajava.blogspot.com/2011/12/thread-affinity-library-for-java.html) 中所建议的那样,具有独立内核(您可以在启动时传递 isolcpus=)也会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多