【发布时间】:2013-04-10 13:08:35
【问题描述】:
我正在编写一个(简单!)线性代数库。在matrix multiplication 的实现中,VisualVM 性能样本告诉我,当乘以大型矩阵 (5k x 120k) 时,该算法将 85% 的时间(特别是“自我时间”)花在以下方法中:
public double next() {
double result;
if(hasNext())
result = vis[i++].next();
else
throw new IllegalStateException("No next value");
return result;
}
无需过多介绍(抱歉,我无法分享更多代码),此方法是矩阵“迭代器”的next() 方法。 (你可以把这个方法所在的类想象成一个由单个列迭代器组成的行迭代器,这些列迭代器存储在vis 中。)我并不感到惊讶,因为它是一个迭代器,所以这个方法被调用了很多次,但是我am 令程序花费大量时间 这个方法感到惊讶。这个方法做的不多,为什么要花时间在这里呢?
以下是我要问的具体问题:
- 我遇到了一些 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
}
提前感谢你们的帮助!
【问题讨论】:
-
我猜这真的取决于 hasNext() 和 next() 调用,因为我们不知道底层对象我不能假设它们是 O(1) 并且该方法应该非常快,即据我们所知,hasNext() 可能会绕太阳转 1000 倍
-
@RuntimeError, "self time" should 只包括在方法本身内花费的时间,所以
hasNext()和 sub-next()调用 should 与归因于此方法的自身时间无关。 (如果您有不同的认识,请纠正我!) -
next是否在调用自身(递归)?如果递归很深,这将是一个很好的理由...... -
@assylias 不,它没有。此
next()方法调用的next()方法位于不同的类中。不过,这点很好。 -
@sigpwned 你的方法很短,所以它可能会在某个阶段被内联,which could confuse the profiler。
标签: java performance optimization visualvm