記錄一次new與clone方法複製對象效率測試

測試clone和new方法的效率差別,首先來反面教材.

public class TestCloneAndNewMain {

public static void main(String[] args) throws CloneNotSupportedException {

    TestClone original = new TestClone("1", "2", "3", "4", "5", "6", "7", "8", "9");
    long l1 = System.currentTimeMillis();
    for (int i = 0; i < 100000000; i++) {
        newCopy(original);
    }
    long l2 = System.currentTimeMillis();

    long l3 = System.currentTimeMillis();
    for (int i = 0; i < 100000000; i++) {
        original.clone();
    }
    long l4 = System.currentTimeMillis();

    System.out.println("new " + (l2 - l1));
    System.out.println("clone " + (l4 - l3));
}

public static TestClone newCopy(TestClone original) {
    TestClone testClone = new TestClone();
    testClone.setValue1(original.getValue1());
    testClone.setValue2(original.getValue2());
    testClone.setValue3(original.getValue3());
    testClone.setValue4(original.getValue4());
    testClone.setValue5(original.getValue5());
    testClone.setValue6(original.getValue6());
    testClone.setValue7(original.getValue7());
    testClone.setValue8(original.getValue8());
    testClone.setValue9(original.getValue9());
    return testClone;
}


static class TestClone implements Cloneable {

    private Integer i;

    private String value1;

    private String value2;

    private String value3;

    private String value4;

    private String value5;

    private String value6;
    private String value7;

    private String value8;

    private String value9;

    public TestClone() {
    }

    public TestClone(String value1, String value2, String value3, String value4, String value5, String value6, String value7, String value8, String value9) {
        this.value1 = value1;
        this.value2 = value2;
        this.value3 = value3;
        this.value4 = value4;
        this.value5 = value5;
        this.value6 = value6;
        this.value7 = value7;
        this.value8 = value8;
        this.value9 = value9;
    }

    public String getValue1() {
        return value1;
    }

    public void setValue1(String value1) {
        this.value1 = value1;
    }

    public String getValue2() {
        return value2;
    }

    public void setValue2(String value2) {
        this.value2 = value2;
    }

    public String getValue3() {
        return value3;
    }

    public void setValue3(String value3) {
        this.value3 = value3;
    }

    public String getValue4() {
        return value4;
    }

    public void setValue4(String value4) {
        this.value4 = value4;
    }

    public String getValue5() {
        return value5;
    }

    public void setValue5(String value5) {
        this.value5 = value5;
    }

    public String getValue6() {
        return value6;
    }

    public void setValue6(String value6) {
        this.value6 = value6;
    }

    public String getValue7() {
        return value7;
    }

    public void setValue7(String value7) {
        this.value7 = value7;
    }

    public String getValue8() {
        return value8;
    }

    public void setValue8(String value8) {
        this.value8 = value8;
    }

    public String getValue9() {
        return value9;
    }

    public void setValue9(String value9) {
        this.value9 = value9;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Integer getI() {
        return i;
    }

    public void setI(Integer i) {
        this.i = i;
    }
}

}

結果
new 9
clone 1688

把new的方法次數X10,clone不變

結果
new 7
clone 1781

次數執行更多,時間反而降低了,超出想象.
這是真的嗎?
這是假的吧.但是這真真實實是結果

當你懷疑人生的時候,就像三體裏面的物理學家質疑基礎物理學一樣.
我給你爲什麼:
現代編譯器是十分聰明的,它們會對你的代碼進行推導分析,判定哪些代碼是無用的然後進行去除,這種行爲對微基準測試是致命的,它會使你無法準確測試出你的方法性能。JMH本身已經對這種情況做了處理,你只要記住:1.永遠不要寫void方法;2.在方法結束返回你的計算結果。有時候如果需要返回多於一個結果,可以考慮自行合併計算結果,或者使用JMH提供的BlackHole對象
那麼我現在就是要用JMH,打破三體人的智子.
結果,clone耗時更少,效率更高.

Benchmark                  Mode  Cnt           Score   Error  Units
TestCloneAndNew.cloneCopy  avgt    2  1200260940.500          ns/op
TestCloneAndNew.newCopy    avgt    2  3277323023.500          ns/op

代碼如下

@BenchmarkMode(Mode.AverageTime)//基準測試類型
@OutputTimeUnit(TimeUnit.NANOSECONDS)//基準測試結果的時間類型
@Warmup(iterations = 10)//預熱的迭代次數
//度量:iterations進行測試的輪次,time每輪進行的時長,timeUnit時長單位,batchSize批次數量
@State(Scope.Thread)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1)
public class TestCloneAndNew {

public static TestClone newCopy(TestClone original) {
    TestClone testClone = new TestClone();
    testClone.setValue1(original.getValue1());
    testClone.setValue2(original.getValue2());
    testClone.setValue3(original.getValue3());
    testClone.setValue4(original.getValue4());
    testClone.setValue5(original.getValue5());
    testClone.setValue6(original.getValue6());
    testClone.setValue7(original.getValue7());
    testClone.setValue8(original.getValue8());
    testClone.setValue9(original.getValue9());
    return testClone;
}

@Benchmark
public void newCopy() {
    TestClone original = new TestClone("1", "2", "3", "4", "5", "6", "7", "8", "9");
    for (int i = 0; i < 100000000; i++) {
        newCopy(original);
    }
}

@Benchmark
public void cloneCopy() throws CloneNotSupportedException {
    TestClone original = new TestClone("1", "2", "3", "4", "5", "6", "7", "8", "9");
    for (int i = 0; i < 100000000; i++) {
        original.clone();
    }
}


public static void main(String[] args) {
    try {
        Options opt = new OptionsBuilder()
                .include(TestCloneAndNew.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    } catch (Exception e) {
        e.printStackTrace();
    }
}


static class TestClone implements Cloneable {

    private Integer i;

    private String value1;

    private String value2;

    private String value3;

    private String value4;

    private String value5;

    private String value6;
    private String value7;

    private String value8;

    private String value9;

    public TestClone() {
    }

    public TestClone(String value1, String value2, String value3, String value4, String value5, String value6, String value7, String value8, String value9) {
        this.value1 = value1;
        this.value2 = value2;
        this.value3 = value3;
        this.value4 = value4;
        this.value5 = value5;
        this.value6 = value6;
        this.value7 = value7;
        this.value8 = value8;
        this.value9 = value9;
    }

    public String getValue1() {
        return value1;
    }

    public void setValue1(String value1) {
        this.value1 = value1;
    }

    public String getValue2() {
        return value2;
    }

    public void setValue2(String value2) {
        this.value2 = value2;
    }

    public String getValue3() {
        return value3;
    }

    public void setValue3(String value3) {
        this.value3 = value3;
    }

    public String getValue4() {
        return value4;
    }

    public void setValue4(String value4) {
        this.value4 = value4;
    }

    public String getValue5() {
        return value5;
    }

    public void setValue5(String value5) {
        this.value5 = value5;
    }

    public String getValue6() {
        return value6;
    }

    public void setValue6(String value6) {
        this.value6 = value6;
    }

    public String getValue7() {
        return value7;
    }

    public void setValue7(String value7) {
        this.value7 = value7;
    }

    public String getValue8() {
        return value8;
    }

    public void setValue8(String value8) {
        this.value8 = value8;
    }

    public String getValue9() {
        return value9;
    }

    public void setValue9(String value9) {
        this.value9 = value9;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Integer getI() {
        return i;
    }

    public void setI(Integer i) {
        this.i = i;
    }
}
}


MAVEN:
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>1.19</version>
        <!--<scope>test</scope>-->
    </dependency>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章