使用访问器/ getter可以更快?

时间:2013-04-17 16:39:38

标签: java performance jvm-hotspot

后台:我打算从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

2 个答案:

答案 0 :(得分:5)

这些简短的方法,如果它们很热(默认设置称为10,000次以上),将由热点内联,所以你不应该注意到性能的差异(你测量性能的方式会忽略许多效果,比如温暖例如,这可能会导致错误的结果。

运行代码并要求热点显示内联内容(-server -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining)时,您会看到下面的输出,其中显示coordproduct内联:

 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];
    }
}

我希望访问者在一个非平凡的场景中花费一点性能(例如,当界面有多个实现时)。但无论如何都要使用访问器界面 - 灵活性和可维护性通常超过性能的几个百分点。