性能异常:相同的循环相差2倍

时间:2018-04-21 13:31:00

标签: java performance

我最初编写此代码来检查将字符串放入缓冲区的最快方法,但很快发现了性能异常。

测试现在包含三个相关方法:'慢'' alpha'和' beta'。 ' alpha'的代码和' beta'是完全一样的。然后我测量用每种方法进行N次迭代所花费的时间,结果发现带有' beta'花费的时间比使用' alpha'的循环多2倍。似乎第3个循环总是比第二个循环慢2倍,即使我交换方法也是如此。

import java.lang.reflect.Field;
import java.nio.ByteBuffer;

public class Main {
    private static final int N = 1_000_000;
    private static Field stringBytes;
    private static String testString;

    static {
        // setup test string:
        StringBuilder builder = new StringBuilder(1024);
        for (int i = 0; i < 100; i++) {
            builder.append("Hello, world!");
        }
        testString = builder.toString();
        // setup String byte array field:
        try {
            Field stringValue = String.class.getDeclaredField("value");
            stringValue.setAccessible(true);
            stringBytes = stringValue;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IllegalAccessException {
        ByteBuffer expectedBuffer = ByteBuffer.allocate(2000)
            .put(testString.getBytes());
        ByteBuffer testBuffer = ByteBuffer.allocate(2000);
        //
        for (int i = 0; i < 10; i++) {
            runTests(testBuffer, expectedBuffer);
        }
    }

    private static void runTests(ByteBuffer testBuffer, ByteBuffer expectedBuffer) throws
        IllegalAccessException {
        long startTime = System.nanoTime();
        for (int i = 0; i < N; i++) {
            testBuffer.clear();
            slow(testBuffer);
            checkResult(testBuffer, expectedBuffer);
        }
        long endTime = System.nanoTime();
        System.out.println("Slow: \t" + (endTime - startTime));
        //
        startTime = System.nanoTime();
        for (int i = 0; i < N; i++) {
            testBuffer.clear();
            alpha(testBuffer);
            checkResult(testBuffer, expectedBuffer);
        }
        endTime = System.nanoTime();
        System.out.println("Alpha: \t" + (endTime - startTime));
        //
        startTime = System.nanoTime();
        for (int i = 0; i < N; i++) {
            testBuffer.clear();
            beta(testBuffer);
            checkResult(testBuffer, expectedBuffer);
        }
        endTime = System.nanoTime();
        System.out.println("Beta: \t" + (endTime - startTime));
    }

    // make sure the JIT doesn't discard computations
    private static void checkResult(ByteBuffer got, ByteBuffer expected) {
        if (!got.equals(expected)) {
            throw new RuntimeException(
                String.format("expected: %s, got %s", expected, got)
            );
        }
    }

    private static void slow(ByteBuffer source) {
        source.put(testString.getBytes());
    }

    private static void alpha(ByteBuffer source) throws IllegalAccessException {
        source.put((byte[]) stringBytes.get(testString));
    }

    private static void beta(ByteBuffer source) throws IllegalAccessException {
        source.put((byte[]) stringBytes.get(testString));
    }
}

什么会导致如此剧烈的性能差异?如何在代码中避免这种差异?

这是运行程序时的输出(非法访问警告除外):

Slow:   4271284211
Alpha:  1089785263
Beta:   1067286082
Slow:   3772404211
Alpha:  1100012164
Beta:   1869625263
Slow:   3779312281
Alpha:  1261239766
Beta:   1949156491
Slow:   3778842573
Alpha:  1067640702
Beta:   1914821988
Slow:   3860709240
Alpha:  1084109473
Beta:   1878945497
Slow:   3662584328
Alpha:  1058276492
Beta:   1819476024
Slow:   3665676725
Alpha:  1061351111
Beta:   1855920467
Slow:   3725946199
Alpha:  1070417778
Beta:   1843628538
Slow:   3666171696
Alpha:  1062847251
Beta:   1829787135
Slow:   3663726784
Alpha:  1055333802
Beta:   1821107836

设置:x64 win10 java9

0 个答案:

没有答案