小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

阿里巴巴技術(shù)門(mén)戶(hù)...

 ShangShujie 2007-05-17
反射的性能到底怎樣?
發(fā)表于: 2007-5-17 下午5:21
附件 image001.gif (22.6 K)
附件 反射的性能.doc (131.5 K)

最近寫(xiě)框架,不可避免的碰到反射的問(wèn)題。一直以來(lái)認(rèn)為反射是相對(duì)比較慢的,干脆寫(xiě)個(gè)程序測(cè)試對(duì)比一下不同的反射方案及性能。

對(duì)于一個(gè)簡(jiǎn)單的對(duì)象:

public static class TestObject {

    private String s ;

    public String getS() {

        return s ;

    }

    public void setS(String s) {

        this . s = s;

    }

}

我比較了四種方案:

1.          直接存取

o.setS( "123" );

o.getS();

這當(dāng)然是最快的方法。

2.          通過(guò)反射存取

Method setter = getMethod (TestObject. class , "setS" , new Class[] { String. class }, false );

Method getter = getMethod (TestObject. class , "getS" , new Class[] {}, false );

setter .invoke(o, new Object[] { "123" });

getter .invoke(o, new Object[0]);

這應(yīng)該是相對(duì)最慢的方法。但究竟慢多少,一會(huì)我們?cè)倏础?

3.          利用 CGLIB FastClass 存取

CGLIB 提供了一個(gè)簡(jiǎn)單的 FastClass 機(jī)制,據(jù)稱(chēng)比 Java 反射快上許多倍,咱們?cè)囈幌驴纯础?

FastClass fc = FastClass. create (TestObject. class );

FastMethod setter = fc .getMethod( "setS" , new Class[] { String. class });

FastMethod getter = fc .getMethod( "getS" , new Class[] {});

setter .invoke(o, new Object[] { "123" });

getter .invoke(o, new Object[0]);

除了類(lèi)名不同以外,其余操作和 JDK 自帶的反射 API 非常相似。

如果你運(yùn)行并跟蹤一下,很容易了解這種 FastClass 的機(jī)制是怎樣工作的。 CGLIB 在運(yùn)行時(shí)生成一個(gè)類(lèi),把反射的調(diào)用轉(zhuǎn)換成直接調(diào)用。通過(guò)跟蹤代碼,很容易得到自動(dòng)生成的二進(jìn)制類(lèi),并用 JAD 反編譯可得類(lèi)似下面的代碼:

public class FastMethod {

    private final FastClass owningClass ;

    private final int methodIndex ;

    public FastMethod(FastClass fc, int index) {

        this . owningClass = fc;

        this . methodIndex = index;

    }

    public Object invoke(Object obj, Object[] args) throws InvocationTargetException {

        return owningClass .invoke( methodIndex , obj, args);

    }

}

class GeneratedFastClass_TestObject extends FastClass {

    public Object invoke( int methodIndex, Object o, Object[] params) {

        switch (methodIndex) {

            case METHOD_SET_S:

                ((TestObject) o).setS((String) params[0]);

                break ;

            case ...

        }

    }

}

使用這種方法的唯一代價(jià)就是:需要為每個(gè)類(lèi)生成一個(gè) FastClass 的實(shí)現(xiàn)。

4.          通過(guò)反射存取,但避開(kāi) Java 安全檢查

Method setter = getMethod (TestObject. class , "setS" , new Class[] { String. class }, false );

Method getter = getMethod (TestObject. class , "getS" , new Class[] {}, false );

setter .setAccessible( true );

getter .setAccessible( true );

setter .invoke(o, new Object[] { "123" });

getter .invoke(o, new Object[0]);

這是我從網(wǎng)上找到的技巧。

現(xiàn)在讓我們就這四種方案,來(lái)測(cè)試一下性能。測(cè)試的方法很簡(jiǎn)單:循環(huán) 1000 萬(wàn)遍,比較時(shí)間。完整的測(cè)試程序如下:

import java.lang.reflect.Method;

import java.text.MessageFormat;

import net.sf.cglib.reflect.FastClass;

import net.sf.cglib.reflect.FastMethod;

public abstract class ReflectionPerformanceTest {

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

        int max = 10000000;

        directAccess .run( "Direct access" , max);

        fastClass .run( "CGLIB Fast Class" , max);

        reflection .run( "JDK reflection" , max);

        reflectionWithoutSecurityCheck .run(

                "JDK reflection without security check" , max);

    }

    private static Method getMethod(Class clazz, String name,

            Class[] paramTypes, boolean noSecurityCheck) {

        Method method;

        try {

            method = clazz.getMethod(name, paramTypes);

        } catch (Exception e) {

            throw new IllegalArgumentException(e);

        }

        if (noSecurityCheck) {

            method.setAccessible( true );

        }

        return method;

    }

    private static ReflectionPerformanceTest directAccess = new ReflectionPerformanceTest() {

        protected void runOnce(TestObject o) throws Exception {

            o.setS( "123" );

            o.getS();

        }

    };

    private static ReflectionPerformanceTest fastClass = new ReflectionPerformanceTest() {

        private FastClass fc = FastClass. create (TestObject. class );

        private FastMethod setter = fc .getMethod( "setS" ,

                new Class[] { String. class });

        private FastMethod getter = fc .getMethod( "getS" , new Class[] {});

        protected void runOnce(TestObject o) throws Exception {

            setter .invoke(o, new Object[] { "123" });

            getter .invoke(o, new Object[0]);

        }

    };

    private static ReflectionPerformanceTest reflection = new ReflectionPerformanceTest() {

        private Method setter = getMethod (TestObject. class , "setS" ,

                new Class[] { String. class }, false );

        private Method getter = getMethod (TestObject. class , "getS" ,

                new Class[] {}, false );

        protected void runOnce(TestObject o) throws Exception {

            setter .invoke(o, new Object[] { "123" });

            getter .invoke(o, new Object[0]);

        }

    };

    private static ReflectionPerformanceTest reflectionWithoutSecurityCheck

                                                              = new ReflectionPerformanceTest() {

        private Method setter = getMethod (TestObject. class , "setS" ,

                new Class[] { String. class }, true );

        private Method getter = getMethod (TestObject. class , "getS" ,

                new Class[] {}, true );

        protected void runOnce(TestObject o) throws Exception {

            setter .invoke(o, new Object[] { "123" });

            getter .invoke(o, new Object[0]);

        }

    };

    public void run(String desc, int max) throws Exception {

        TestObject o = new TestObject();

        long start = System. currentTimeMillis ();

        for ( int i = 0; i < max; i++) {

            runOnce(o);

        }

        System. out .println(MessageFormat. format (

                "duration={1,number,####,###} ms - {0}" , new Object[] { desc,

                        new Long(System. currentTimeMillis () - start) }));

    }

    protected abstract void runOnce(TestObject o) throws Exception;

    public static class TestObject {

        private String s ;

        public String getS() {

            return s ;

        }

        public void setS(String s) {

            this . s = s;

        }

    }

}

下面是在不同的 JDK 下的測(cè)試結(jié)果:(我的機(jī)器是 Core 2 Dual 2.66MHz

JDK 1.4.2

duration=122 ms - Direct access

duration=936 ms - CGLIB Fast Class

duration=3,809 ms - JDK reflection

duration=1,605 ms - JDK reflection without security check

JDK 1.5.0

duration=83 ms - Direct access

duration=655 ms - CGLIB Fast Class

duration=3,150 ms - JDK reflection

duration=896 ms - JDK reflection without security check

JDK 1.6.0

duration=113 ms - Direct access

duration=562 ms - CGLIB Fast Class

duration=2,384 ms - JDK reflection

duration=743 ms - JDK reflection without security check

上述數(shù)據(jù)畫(huà)成圖表更直觀:( 比較矮的是比較好的

圖表 

觀察:

l   新一代的 JDK 比上一代 JDK 性能提升非常明顯,只是 JDK 1.6.0 在直接訪問(wèn)時(shí)性能反常地輸給 JDK 1.5.0 。

l   直接訪問(wèn)在性能上占有絕對(duì)的優(yōu)勢(shì),約比 Java 反射快上 20 JDK 1.6.0 )到 30 倍( JDK 1.4.2 )左右。

l   CGLIB FastClass 的效果還是不錯(cuò)的,比直接訪問(wèn)慢 5 JDK1.6.0 )到 10 倍( JDK 1.4.2 ),比 Java 反射快 4 倍左右。

l   另人驚異的是,如果把“安全檢查”關(guān)掉,再調(diào)用 Java 反射,其結(jié)果和 CGLIB FastClass 極其接近,比普通的 Java 反射快 3 4 倍左右。沒(méi)想到 Java 反射居然把大量時(shí)間用在這里了。

結(jié)論:

l   Java 反射比直接訪問(wèn)要慢 20 倍,但別忘了我們測(cè)試了 1000 萬(wàn)次。實(shí)際單次訪問(wèn)的絕對(duì)時(shí)間差別,還是極其微小的。

l   CGLib FastClass 的效果不錯(cuò),然而你必須附帶 CGLIB 這個(gè)類(lèi)庫(kù),而且在運(yùn)行時(shí)要承擔(dān)動(dòng)態(tài)生成大量類(lèi)的時(shí)間和空間。

l   把“安全檢查”關(guān)掉,再用正常的方法調(diào)用 Java 反射,可以取得和 CGLIB FastClass 極為接近的效果,但卻少了 CGLIB 的代價(jià)。因此如果 security 策略許可的話,這是最好的方案。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多