| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
29 | 30 | 1 | 2 | 3 | 4 | 5 | |||
6 | 7 | 8 | 9 | 10 | 11 | 12 | |||
13 | 14 | 15 | 16 | 17 | 18 | 19 | |||
20 | 21 | 22 | 23 | 24 | 25 | 26 | |||
27 | 28 | 29 | 30 | 31 | 1 | 2 | |||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
jni的幾個基本的性能測試分析
今天對jvm運行jni做了幾個基本的性能測試,測試的jvm有jdk1.4.2_19、jdk1.5.0_04和jdk1.6.0_14,測試的重復(fù)次數(shù)都是一億次,測試結(jié)果的絕對數(shù)值意義不大,僅供參考。
java調(diào)用jni空函數(shù)和調(diào)用java方法的性能(比較):
java.version = 1.6.0_14
Java空方法調(diào)用 耗時 329 ms 平均每秒 303951367
JNI空方法調(diào)用 耗時 1531 ms 平均每秒 65316786
java.version = 1.5.0_04
java空方法調(diào)用 耗時 312 ms 平均每秒 320512820
JNI空方法調(diào)用 耗時 1891 ms 平均每秒 52882072
java.version = 1.4.2_19
java空方法調(diào)用 耗時 312 ms 平均每秒 320512820
JNI空方法調(diào)用 耗時 3672 ms 平均每秒 27233115
jdk版本越高,JNI調(diào)用的性能越好,這點要感謝sun的努力了。
在jdk1.6下,僅僅是空方法調(diào)用,JNI的性能就要比java內(nèi)部調(diào)用慢將近5倍,而在jdk1.4下更是慢了十多倍。
jni里查找class(JNIEnv.FindClass)和fieldid(JNIEnv.GetFieldID)和jni讀取java Field(JNIEnv.GetFieldValue)的性能:
緩存表示只調(diào)用一次,不緩存就是每次都調(diào)用。
java.version = 1.6.0_14
JNI 字段讀取 (緩存Class=false ,緩存字段ID=false) 耗時 : 79172 ms 平均每秒 : 1263072
JNI 字段讀取 (緩存Class=true ,緩存字段ID=false) 耗時 : 25015 ms 平均每秒 : 3997601
JNI 字段讀取 (緩存Class=false ,緩存字段ID=true) 耗時 : 50765 ms 平均每秒 : 1969861
JNI 字段讀取 (緩存Class=true ,緩存字段ID=true) 耗時 : 2125 ms 平均每秒 : 47058823
java.version = 1.5.0_04
JNI 字段讀取 (緩存Class=false ,緩存字段ID=false) 耗時 : 87109 ms 平均每秒 : 1147987
JNI 字段讀取 (緩存Class=true ,緩存字段ID=false) 耗時 : 32031 ms 平均每秒 : 3121975
JNI 字段讀取 (緩存Class=false ,緩存字段ID=true) 耗時 : 51657 ms 平均每秒 : 1935846
JNI 字段讀取 (緩存Class=true ,緩存字段ID=true) 耗時 : 2187 ms 平均每秒 : 45724737
java.version = 1.4.2_19
JNI 字段讀取 (緩存Class=false ,緩存字段ID=false) 耗時 : 97500 ms 平均每秒 : 1025641
JNI 字段讀取 (緩存Class=true ,緩存字段ID=false) 耗時 : 38110 ms 平均每秒 : 2623983
JNI 字段讀取 (緩存Class=false ,緩存字段ID=true) 耗時 : 55204 ms 平均每秒 : 1811462
JNI 字段讀取 (緩存Class=true ,緩存字段ID=true) 耗時 : 4187 ms 平均每秒 : 23883448
查找class和ID(field和method)消耗大量的時間。只是讀取字段值的時間基本上跟上面的JNI空方法是一個數(shù)量級。
而如果每次都根據(jù)名稱查找class和field的話,性能要下降高達40倍。
讀取一個字段值的性能在百萬級上,在交互頻繁的JNI應(yīng)用中是不能忍受的。
消耗時間最多的就是查找class,因此在Native里保存class和member id是必要的。
class和member id在一定范圍內(nèi)是穩(wěn)定的,但在動態(tài)加載的class loader下,保存全局的class要么可能失效,要么可能造成無法卸載classloader,
在諸如OSGI框架下的JNI應(yīng)用還要特別注意這方面的問題。
在讀取字段值和查找FieldID上,jdk1.4和1.5、1.6的差距是非常明顯的。但在最耗時的查找class上,三個版本沒有明顯差距。
基于線程變量(TlsSetValue/TlsGetValue)的JNIEnv讀取和基于JavaVM的JNIEnv讀取(JavaVM.GetEnv)
JNIEnv讀取 (線程變量) 耗時 : 516 ms 平均每秒 : 193798449
java.version = 1.6.0_14
JNIEnv讀取 (JavaVM) 耗時 : 1985 ms 平均每秒 : 50377833
java.version = 1.5.0_04
JNIEnv讀取 (JavaVM) 耗時 : 2218 ms 平均每秒 : 45085662
java.version = 1.4.2_19
JNIEnv讀取 (JavaVM) 耗時 : 2234 ms 平均每秒 : 44762757
為什么要做這個JNIEnv讀取測試:
JavaVM是進程全局有效的,而JNIEnv是線程相關(guān)的,
但JNI編程是可以不用這樣的模式來獲得JNIEnv的,需要在所有相關(guān)的函數(shù)調(diào)用里帶JNIEnv參數(shù)。
在C++編程模式下,大量的對象方法調(diào)用都要帶JNIEnv的參數(shù)確實不如動態(tài)獲得它方便。
在性能可以接受的范圍內(nèi)是可以考慮用其他的模式來隨時獲得JNIEnv的。因此我才會做這個測試。
從上面的測試數(shù)據(jù)看,用線程變量的性能是優(yōu)于JavaVM.GetEnv的,而且從相對的數(shù)量級上看,個人認為是完全可以接受這種JNIEnv的獲得模式的。
希望以上的測試分析對大家的JNI應(yīng)用開發(fā)和優(yōu)化有一定的參考價值。
java反編譯+UI輔助工具
反編譯引擎是自己寫的,一次發(fā)布到公共網(wǎng)絡(luò)上,
UI輔助工具包含很多方便的功能,可以直接查看jar文件、可以模糊查找類名、查看繼承關(guān)系、查找引用、查找字符串等。
歡迎大家去試用一下。
第一次使用BlogJava,不知道怎樣提供下載地址,哪位朋友介紹一下
http://www.aygfsteel.com/Files/taolei/classexplorer.zip
如果這個不行可以在
http://taolei.download.csdn.net/
下載