【问题标题】:CPU load from Java来自 Java 的 CPU 负载
【发布时间】:2010-10-12 16:26:06
【问题描述】:

有没有办法在不使用 JNI 的情况下获取 Java 下的当前 cpu 负载?

【问题讨论】:

    标签: java profiling


    【解决方案1】:

    getSystemLoadAverage() 为您提供超过 1 分钟的时间(每秒刷新一次),并为整个操作系统提供此值。应该通过分别监控每个线程来完成更实时的概览。重要的是还要注意监视刷新间隔 - 您更频繁地检查值,在给定时刻更精确,如果您每毫秒执行一次,它通常是 0 或 100(或更多取决于有多少 CPU)。但是,如果我们允许时间范围(例如 1 秒),我们会得到这段时间的平均值,并且我们会得到更多信息量的结果。此外,需要注意的是,只有一个线程占用多个 CPU(内核)的可能性很小。

    以下实现允许使用 3 种方法:

    • getTotalUsage() - JVM 中所有线程的总负载
    • getAvarageUsagePerCPU() - 每个 CPU(核心)的平均负载
    • getUsageByThread(Thread t) - 指定线程的总负载

      import java.lang.management.ManagementFactory;
      import java.lang.management.OperatingSystemMXBean;
      import java.lang.management.ThreadMXBean;
      import java.util.Collection;
      import java.util.HashMap;
      import java.util.HashSet;
      import java.util.Map;
      import java.util.Set;
      
      public class MonitoringThread extends Thread {
      
          private long refreshInterval;
          private boolean stopped;
      
          private Map<Long, ThreadTime> threadTimeMap = new HashMap<Long, ThreadTime>();
          private ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
          private OperatingSystemMXBean opBean = ManagementFactory.getOperatingSystemMXBean();
      
          public MonitoringThread(long refreshInterval) {
              this.refreshInterval = refreshInterval;
      
              setName("MonitoringThread");
      
              start();
          }
      
          @Override
          public void run() {
              while(!stopped) {
                  Set<Long> mappedIds;
                  synchronized (threadTimeMap) {
                      mappedIds = new HashSet<Long>(threadTimeMap.keySet());
                  }
      
                  long[] allThreadIds = threadBean.getAllThreadIds();
      
                  removeDeadThreads(mappedIds, allThreadIds);
      
                  mapNewThreads(allThreadIds);
      
                  Collection<ThreadTime> values;
                  synchronized (threadTimeMap) {
                      values = new HashSet<ThreadTime>(threadTimeMap.values());    
                  }
      
                  for (ThreadTime threadTime : values) {
                      synchronized (threadTime) {
                          threadTime.setCurrent(threadBean.getThreadCpuTime(threadTime.getId())); 
                      }
                  }
      
                  try {
                      Thread.sleep(refreshInterval);
                  } catch (InterruptedException e) {
                      throw new RuntimeException(e);
                  }
      
                  for (ThreadTime threadTime : values) {
                      synchronized (threadTime) {
                          threadTime.setLast(threadTime.getCurrent());    
                      }
                  }
              }
          }
      
          private void mapNewThreads(long[] allThreadIds) {
              for (long id : allThreadIds) {
                  synchronized (threadTimeMap) {
                      if(!threadTimeMap.containsKey(id))
                          threadTimeMap.put(id, new ThreadTime(id));
                  }
              }
          }
      
          private void removeDeadThreads(Set<Long> mappedIds, long[] allThreadIds) {
              outer: for (long id1 : mappedIds) {
                  for (long id2 : allThreadIds) {
                      if(id1 == id2)
                          continue outer;
                  }
                  synchronized (threadTimeMap) {
                      threadTimeMap.remove(id1);
                  }
              }
          }
      
          public void stopMonitor() {
              this.stopped = true;
          }
      
          public double getTotalUsage() {
              Collection<ThreadTime> values;
              synchronized (threadTimeMap) {
                  values = new HashSet<ThreadTime>(threadTimeMap.values());    
              }
      
              double usage = 0D;
              for (ThreadTime threadTime : values) {
                  synchronized (threadTime) {
                      usage += (threadTime.getCurrent() - threadTime.getLast()) / (refreshInterval * 10000);
                  }
              }
              return usage;
          }
      
          public double getAvarageUsagePerCPU() {
              return getTotalUsage() / opBean.getAvailableProcessors(); 
          }
      
          public double getUsageByThread(Thread t) {
              ThreadTime info;
              synchronized (threadTimeMap) {
                  info = threadTimeMap.get(t.getId());
              }
      
              double usage = 0D;
              if(info != null) {
                  synchronized (info) {
                      usage = (info.getCurrent() - info.getLast()) / (refreshInterval * 10000);
                  }
              }
              return usage;
          }
      
          static class ThreadTime {
      
              private long id;
              private long last;
              private long current;
      
              public ThreadTime(long id) {
                  this.id = id;
              }
      
              public long getId() {
                  return id;
              }
      
              public long getLast() {
                  return last;
              }
      
              public void setLast(long last) {
                  this.last = last;
              }
      
              public long getCurrent() {
                  return current;
              }
      
              public void setCurrent(long current) {
                  this.current = current;
              }
          }
      }
      

    【讨论】:

      【解决方案2】:

      如果您使用的是JRockit JVM,您可以使用JMAPI。它适用于 JDK 1.4、1.5 和 1.6。

      System.out.println("Total CPU-usage:" + JVMFactory.getJVM().getMachine().getCPULoad());
      
      System.out.println("Total JVM-load :" + JVMFactory.getJVM().getJVMLoad());
      
      for(Iterator it = JVMFactory.getJVM().getMachine().getCPUs().iterator(); it.hasNext();)
      {
         CPU cpu = (CPU)it.next();
         System.out.println("CPU Description: " + cpu.getDescription());
         System.out.println("CPU Clock Frequency: " + cpu.getClockFrequency());
         System.out.println("CPU Load: " + cpu.getLoad());
         System.out.println();
      }
      

      【讨论】:

        【解决方案3】:

        这确实涉及 JNI,但 Hyperic 有一个名为 Sigar 的 GPL 库,它为所有主要平台提供此信息,以及一堆其他依赖于操作系统的统计信息,如磁盘使用情况。它对我们很有用。

        【讨论】:

          【解决方案4】:

          【讨论】:

            【解决方案5】:

            在 linux 上,您可以只读取文件 /proc/loadavg,其中前三个值表示负载平均值。对于 Windows,您可能必须坚持使用 JNI。

            【讨论】:

              【解决方案6】:

              在 Linux 下,您可以使用 Runtime.exec() 来执行“正常运行时间”并评估输出。我不认为在 Linux 下有更好的方法,我认为在 Windows 下也没有同样“方便”的方法。

              【讨论】:

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