Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java VisualVM-奇怪的自我时间_Java_Profiling_Visualvm - Fatal编程技术网

Java VisualVM-奇怪的自我时间

Java VisualVM-奇怪的自我时间,java,profiling,visualvm,Java,Profiling,Visualvm,今天我被我得到的可视化虚拟机评测结果弄糊涂了 我有以下简单的Java方法: public class Encoder { ... private BitString encode(InputStream in, Map<Character, BitString> table) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(in)

今天我被我得到的可视化虚拟机评测结果弄糊涂了

我有以下简单的Java方法:

public class Encoder {
  ...
  private BitString encode(InputStream in, Map<Character, BitString> table) 
      throws IOException {

    BufferedReader reader = new BufferedReader(new InputStreamReader(in));

    BitString result = new BitString();
    int i;
    while ((i = reader.read()) != -1) {
      char ch = (char) i;
      BitString string = table.get(ch);
      result = result.append(string);
    }

    return result;
  }
}
然而,当我尝试使用VisualVM验证发生了什么时,我得到了以下结果:

一般来说,我对可视化虚拟机和评测的经验很少。据我所知,问题似乎出在
encode
方法本身的某个地方,而不是
append

可以肯定的是,我将整个encode方法和append调用与自定义时间测量结合起来,如下所示:

public class Encoder {
  private BitString encode(InputStream in, Map<Character, BitString> table)
      throws IOException {

>>  long startTime = System.currentTimeMillis();
>>  long appendDuration = 0;

    BufferedReader reader = new BufferedReader(new InputStreamReader(in));

    BitString result = new BitString();
    int i;
>>  long count = 0;
    while ((i = reader.read()) != -1) {
      char ch = (char) i;
      BitString string = table.get(ch);

>>    long appendStartTime = System.currentTimeMillis();
      result = result.append(string);
>>    long appendEndTime = System.currentTimeMillis();
>>    appendDuration += appendEndTime - appendStartTime;

>>    count++;
>>    if (count % 1000 == 0) {
>>      log.info(">>> CHARACTERS PROCESSED: " + count);
>>      long endTime = System.currentTimeMillis();
>>      log.info(">>> TOTAL ENCODE DURATION: " + (endTime - startTime) + " ms");
>>      log.info(">>> TOTAL APPEND DURATION: " + appendDuration + " ms");
>>    }
    }

    return result;
  }
}
这似乎与VisualVM的结果相矛盾


我遗漏了什么?

[这个答案是无效的。但我会一直保留它,直到得到会员的帮助,因为这篇文章包含了两条注释,可以帮助其他人理解这个问题]

在本例中,VisualVM测量了实际的CPU时间,但测量的时间值是“经过的时间”


如果执行线程必须等待IO或网络,那么该时间将不会被测量为CPU时间。

您会看到这种行为,因为VisualVM只能在安全点对调用堆栈进行采样,而JVM正在优化代码中的安全点。这导致样本被集中在“自我时间”下,这使得它被人为夸大和误导。有两种可能的修复方法:

  • 为了使VisualVM更好地工作,添加JVM选项以保留更多安全点,如
    -XX:-Inline
    -XX:+UseCountedLoopSafepoints
    。这将使代码速度降低一些,但会使分析结果更加准确。这个解决方案很简单,而且通常已经足够好了。只要记住在不进行评测时删除这些选项
  • 如果您不介意切换探查器,可以使用或。它们能够使用JVM的特殊API在safepoints以外的地方采集样本。这个解决方案更准确一些,因为您正在评测完全优化的代码,但在我看来,这些评测器比VisualVM更难使用
在您的特定情况下,JVM可能正在内联对
BitString.append()
的方法调用以提高性能。这会导致通常位于方法调用末尾的safepoint被删除,这意味着该方法将不再显示在探查器中


有一篇精彩的博文,详细介绍了什么是safepoints以及它们是如何工作的,还有一篇博文更详细地介绍了safepoints和采样分析器之间的交互作用。

您是如何测量时间的,你能不能也加上这个代码。我加上了时间测量的解释,还有
append
的代码。我认为没有任何IO或网络在那里等待。也许GC暂停了?你试过了吗?它可以很好地与Java配合使用,并将准确地告诉您时间的去向。注意,它不能测量。相反,它利用了一个事实,即该活动需要花费大量的时间来确定它的位置。您可以使用它来获得非常粗略的测量,但它可以精确地发现问题。请参阅我的扩展答案-我包括了
append
的实现。我认为那里没有做任何IO。也许更喜欢暂停?但是,正如您在屏幕截图中看到的,VisualVM显示了两个值—
Time
Time(CPU)
时间
不是经过的时间和
时间(CPU)
是实际的CPU时间吗?是的,你是对的,这里有些奇怪,我的答案对你的情况无效。对于2次编码调用,append只被调用了4次。乍一看,所有调用都没有被记录。熟悉VisuvalVM的人可能会帮助您。根据我在JProfiler上的经验,我试图帮助你。谢谢
public class Encoder {
  private BitString encode(InputStream in, Map<Character, BitString> table)
      throws IOException {

>>  long startTime = System.currentTimeMillis();
>>  long appendDuration = 0;

    BufferedReader reader = new BufferedReader(new InputStreamReader(in));

    BitString result = new BitString();
    int i;
>>  long count = 0;
    while ((i = reader.read()) != -1) {
      char ch = (char) i;
      BitString string = table.get(ch);

>>    long appendStartTime = System.currentTimeMillis();
      result = result.append(string);
>>    long appendEndTime = System.currentTimeMillis();
>>    appendDuration += appendEndTime - appendStartTime;

>>    count++;
>>    if (count % 1000 == 0) {
>>      log.info(">>> CHARACTERS PROCESSED: " + count);
>>      long endTime = System.currentTimeMillis();
>>      log.info(">>> TOTAL ENCODE DURATION: " + (endTime - startTime) + " ms");
>>      log.info(">>> TOTAL APPEND DURATION: " + appendDuration + " ms");
>>    }
    }

    return result;
  }
}
CHARACTERS PROCESSED: 102000
TOTAL ENCODE DURATION: 188276 ms
APPEND CALL DURATION: 188179 ms