Java 6 和 7 之间的区别是什么,会导致性能问题?

2022-09-01 19:33:55

我对Java 7的一般经验告诉我,它比Java 6更快。但是,我遇到了足够的信息,使我相信情况并非总是如此。

第一点信息来自这里找到的Minecraft Snooper数据。我的目的是查看这些数据,以确定用于启动Minecraft的不同开关的效果。例如,我想知道使用-Xmx4096m对性能是否有负面影响或积极影响。在我到达那里之前,我查看了正在使用的不同版本的Java。它涵盖了从1.5到使用1.8的开发人员的所有内容。通常,随着Java版本的增加,您会看到fps性能的提高。在1.6的不同版本中,您甚至可以看到这种逐渐上升的趋势。老实说,我没想到会看到那么多不同版本的java仍然在野外,但我想人们并没有像他们应该的那样运行更新。

在1.6的更高版本的某个时候,你会得到最高的一瞥。1.7的平均性能低于1.6的更高版本,但仍然高于1.6的早期版本。在我自己系统的样本上,几乎不可能看到差异,但是当查看更广泛的样本时,它很清楚。

为了控制有人可能已经找到了Java的神奇开关的可能性,我通过仅查看数据而不传递任何开关来控制。这样,在我开始查看不同的标志之前,我就可以有一个合理的控制。

我驳回了我所看到的大部分内容,因为这可能是一些有人没有与我分享的Magic Java 6。

现在我一直在做另一个项目,它要求我在输入流中传递一个数组,由另一个API处理。最初,我使用ByteArrayInputStream,因为它可以开箱即用。当我查看它的代码时,我注意到每个函数都是同步的。由于这对于这个项目来说是不必要的,我重写了一个去掉了同步。然后我决定,我想知道在这种情况下,同步的一般成本对我来说是多少。

我模拟了一个简单的测试,只是为了看看。我使用System.nanoTime()对所有内容进行了计时,并使用Java 1.6_20 x86和1.7.0-b147 AMD64,以及1.7_15 AMD64并使用-server。我预计AMD64版本仅在基于架构方面就表现出色,并具有任何java 7优势。我还查看了第25,第50和第75百分位(蓝色,红色,绿色)。然而,没有-服务器的1.6击败了所有其他配置的裤子。graph

所以我的问题是。1.6 -server 选项中有哪些内容会影响性能,而在 1.7 中也默认为 on?

我知道1.7中的大部分速度增强来自1.6中默认的一些更激进的性能选项,但其中之一是导致性能差异。我只是不知道该看哪一个。

public class ByteInputStream extends InputStream {

public static void main(String args[]) throws IOException {
    String song = "This is the song that never ends";
    byte[] data = song.getBytes();
    byte[] read = new byte[data.length];
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    ByteInputStream bis = new ByteInputStream(data);

    long startTime, endTime;

    for (int i = 0; i < 10; i++) {
        /*code for ByteInputStream*/
        /*
        startTime = System.nanoTime();
        for (int ctr = 0; ctr < 1000; ctr++) {
            bis.mark(0);
            bis.read(read);
            bis.reset();
        }
        endTime = System.nanoTime(); 

        System.out.println(endTime - startTime); 
        */

        /*code for ByteArrayInputStream*/
        startTime = System.nanoTime();
        for (int ctr = 0; ctr < 1000; ctr++) {
            bais.mark(0);
            bais.read(read);
            bais.reset();
        }
        endTime = System.nanoTime();

        System.out.println(endTime - startTime);
    }

}

private final byte[] array;
private int pos;
private int min;
private int max;
private int mark;

public ByteInputStream(byte[] array) {
    this(array, 0, array.length);
}

public ByteInputStream(byte[] array, int offset, int length) {
    min = offset;
    max = offset + length;
    this.array = array;
    pos = offset;
}

@Override
public int available() {
    return max - pos;
}

@Override
public boolean markSupported() {
    return true;
}

@Override
public void mark(int limit) {
    mark = pos;
}

@Override
public void reset() {
    pos = mark;
}

@Override
public long skip(long n) {
    pos += n;
    if (pos > max) {
        pos = max;
    }
    return pos;
}

@Override
public int read() throws IOException {
    if (pos >= max) {
        return -1;
    }
    return array[pos++] & 0xFF;
}

@Override
public int read(byte b[], int off, int len) {
    if (pos >= max) {
        return -1;
    }
    if (pos + len > max) {
        len = max - pos;
    }
    if (len <= 0) {
        return 0;
    }
    System.arraycopy(array, pos, b, off, len);
    pos += len;
    return len;
}

@Override
public void close() throws IOException {
}

}// end class

答案 1

我认为,正如其他人所说,你的测试太短了,无法看到核心问题 - 图表显示了nanoTime,这意味着被测量的核心部分在0.0001到0.0006s内完成。

讨论

-server 和 -client 的主要区别在于 -server 期望 JVM 存在很长时间,因此在早期花费精力以获得更好的长期结果。-客户端旨在实现快速的启动时间和足够好的性能。

特别是热点运行具有更多的优化,并且这些优化需要更多的CPU来执行。换句话说,使用 -server,您可能会看到优化器的成本超过了优化的任何收益。

看到“java -server”和“java -client”之间的真正区别了吗?

或者,您可能还会看到分层编译的效果,在 Java 7 中,热点不会那么快启动。只有 1000 次迭代,代码的全面优化要到以后才能完成,因此收益会更小。

如果您使用JVM将转储有关在解释和编译的各种方法中花费的时间的一些数据来运行java,您可能会获得见解。它应该给出一个关于编译的内容的想法,以及热点启动之前的(cpu)时间的比率。-Xprof

但是,要获得真实的图像,您确实需要运行更长的时间 - 几秒钟的分钟,而不是毫秒 - 以使Java和操作系统能够预热。最好将测试循环(这样您就有一个包含已检测主测试循环的循环),以便您可以忽略预热。main

编辑将秒数更改为分钟,以确保热点、jvm 和操作系统正确“预热”


答案 2

推荐