【发布时间】:2016-09-24 17:00:00
【问题描述】:
今天我对我得到的 Visual VM 分析结果感到困惑。
我有以下简单的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;
}
}
此方法从流中读取字符,一次一个。对于每个字符,它会查找它的位串表示,并将这些位串连接起来以表示整个流。
BitString 是一种自定义数据结构,它使用底层字节数组表示位序列。
该方法的性能很差。问题在于BitString#append - 该方法创建一个新的字节数组,从两个输入 BitString 复制位并将其作为新的 BitString 实例返回。
public BitString append(BitString other) {
BitString result = new BitString(size + other.size);
int pos = 0;
for (byte b : this) {
result.set(pos, b);
pos++;
}
for (byte b : other) {
result.set(pos, b);
pos++;
}
return result;
}
但是,当我尝试使用 VisualVM 来验证发生了什么时,我得到了以下结果:
我对 Visual VM 和一般分析的经验很少。据我了解,这看起来好像问题在于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;
}
}
我得到了以下结果:
CHARACTERS PROCESSED: 102000
TOTAL ENCODE DURATION: 188276 ms
APPEND CALL DURATION: 188179 ms
这似乎与 Visual VM 的结果相矛盾。
我错过了什么?
【问题讨论】:
-
你是如何测量时间的,能否请你也添加那个代码。
-
我添加了如何测量时间的解释以及
append的代码。我认为那里没有任何 IO 或网络等待。也许 GC 会暂停? -
你试过this method吗?它适用于 Java,并且会准确地告诉你时间去哪儿了。请注意,它不测量。相反,它利用了活动需要花费大量时间来确定它的事实。您可以使用它进行非常粗略的测量,但它可以准确地发现问题。