后台:我打算从C ++到Java port a library I have written。代码处理 n d - 维度点的大小 n 的列表,需要计算标量产品等。我想让我的代码独立于点的存储格式和为此目的介绍了一个接口,
public interface PointSetAccessor
{
float coord(int p, int c);
}
允许我获取 p的 c -th坐标(0≤ c < d ) -th point(0≤ p < n )。
问题:由于代码必须非常快,我想知道这是否会降低性能,与直接访问模式(如points[p][c]
相比,其中{{1}是一个 n 数组的数组,每个数组都包含 d 点坐标。
令人惊讶的是,情况恰恰相反:通过points
进行“间接”访问,代码(见下文)快20%。 (我使用PointSetAccessor
进行了测量,前者为14s,后者为11s。)
问题:知道为什么会这样吗?好像Hotspot决定更积极地进行优化,或者在后一版本中有更大的自由度?
代码(计算无意义):
time java -server -XX:+AggressiveOpts -cp bin Speedo
答案 0 :(得分:5)
这些简短的方法,如果它们很热(默认设置称为10,000次以上),将由热点内联,所以你不应该注意到性能的差异(你测量性能的方式会忽略许多效果,比如温暖例如,这可能会导致错误的结果。
运行代码并要求热点显示内联内容(-server -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
)时,您会看到下面的输出,其中显示coord
和product
内联:
76 1 % javaapplication27.Speedo::main @ -2 (163 bytes) made not entrant
77 6 javaapplication27.Speedo$ArrayPointSetAccessor::coord (9 bytes)
78 7 javaapplication27.Speedo::product (45 bytes)
@ 18 javaapplication27.Speedo$ArrayPointSetAccessor::coord (9 bytes) inline (hot)
@ 27 javaapplication27.Speedo$ArrayPointSetAccessor::coord (9 bytes) inline (hot)
80 2 % javaapplication27.Speedo::main @ 101 (163 bytes)
@ 118 javaapplication27.Speedo::product (45 bytes) inline (hot)
@ 18 javaapplication27.Speedo$ArrayPointSetAccessor::coord (9 bytes) inline (hot)
@ 27 javaapplication27.Speedo$ArrayPointSetAccessor::coord (9 bytes) inline (hot)
答案 1 :(得分:2)
如果你真的担心性能问题,你应该研究什么摆脱二维数组(用一维数组取代)会买你。
java中的多维数组比大多数其他语言更昂贵,因为java将它们实现为数组数组(具有N维,任何小于N的维是对下一维的引用数组)。
对于你的float [50000] [10],这意味着有一个50000引用浮点数的数组[10]。由于每个数组也是一个对象(带有几个字节的头)。由于最后一个维度很小(10),因此在内存使用方面的开销很大(相反的情况下,float [10] [50000]的内存占用量相当小)。
尝试这样的内存布局:
public static final class ArrayPointSetAccessor implements PointSetAccessor {
private final int dimSize;
private final float[] array;
public ArrayPointSetAccessor(float[] array, int dimSize) {
this.dimSize = dimSize;
this.array = array;
}
public float coord(int point, int dim) {
return array[dim * dimSize + point];
}
}
我希望访问者在一个非平凡的场景中花费一点性能(例如,当界面有多个实现时)。但无论如何都要使用访问器界面 - 灵活性和可维护性通常超过性能的几个百分点。