我正在编写一个(简单!)线性代数库。在执行matrix multiplication , 一个 VisualVM性能示例告诉我,在乘以大型矩阵 (5k x 120k) 时,该算法在以下方法中花费了 85% 的时间(特别是“ self 时间”):
public double next() {
double result;
if(hasNext())
result = vis[i++].next();
else
throw new IllegalStateException("No next value");
return result;
}
无需赘述(抱歉,我无法分享更多代码),此方法是矩阵“迭代器”的 next()
方法。 (您可以将此方法所在的类想象成一个由单独的列迭代器组成的行迭代器,这些迭代器存储在 vis
中。)我对此方法被频繁调用并不感到惊讶,因为它是一个迭代器,但令我惊讶的是该程序在该方法中花费了大量时间。这个方法做的不多,为什么要花时间在这里呢?
以下是我要问的具体问题:
- 我遇到了 VisualVM 的一些“陷阱”吗?例如,JIT 是否会以某种方式混淆 VisualVM,导致 VisualVM 将时间归因于错误的方法?
- 为什么程序要花时间在这里?该方法只是没有做太多。特别是,我不认为缓存效应可以解释这个问题,因为
vis
数组比要相乘的矩阵数据小得多。
如果它有用,这里有一个 jad反汇编我上面粘贴的方法:
public double next()
{
double result;
if(hasNext())
//* 0 0:aload_0
//* 1 1:invokevirtual #88 <Method boolean hasNext()>
//* 2 4:ifeq 32
result = vis[i++].next();
// 3 7:aload_0
// 4 8:getfield #42 <Field VectorIterator[] vis>
// 5 11:aload_0
// 6 12:dup
// 7 13:getfield #28 <Field int i>
// 8 16:dup_x1
// 9 17:iconst_1
// 10 18:iadd
// 11 19:putfield #28 <Field int i>
// 12 22:aaload
// 13 23:invokeinterface #72 <Method double VectorIterator.next()>
// 14 28:dstore_1
else
//* 15 29:goto 42
throw new IllegalStateException("No next value");
// 16 32:new #89 <Class IllegalStateException>
// 17 35:dup
// 18 36:ldc1 #91 <String "No next value">
// 19 38:invokespecial #93 <Method void IllegalStateException(String)>
// 20 41:athrow
return result;
// 21 42:dload_1
// 22 43:dreturn
}
在此先感谢您的帮助!
最佳答案
我发现这个方法看起来像一个热点,因为 VisualVM 被指示在其分析中忽略来自 JRE 的方法。花在那些“被忽略”方法上的时间(表面上)被卷入调用堆栈最顶层未被忽略的条目的自身时间。
下面是 VisualVM 中的设置屏幕,包括导致数据错误的“不分析包”设置。要调整“忽略类别”设置,您必须 (1) 单击以红色突出显示的“设置”复选框,然后 (2) 调整以蓝色突出显示的类别设置。
根据您的操作,至少不要忽略 java.*
和 javax.*
包可能是有意义的。
关于java - 为什么这种方法成为热点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16065668/