原文鏈接How Slow is Reflection in Android?
??到目前為止,我們分析了大量的app,并且發現了一小部分減緩Android速度的原因,在這篇文章中,我們將一個一個的來描述。
??反射在Java或Android開發中當然是一個很有用的方面。但是這常常也是減緩app速度的來源。接下來看幾個例子。
兩個例子
??第一個例子和NYTimes這個Android app有關。得到NimbleDroid的幫忙,我們的朋友在NYTimes上發現了Gson的反射類型適配器花費了700ms的啟動延時。他們最后通過重寫自定義適配器來解決了這個問題。
??我們的第二個例子和Photobucket有關,這是一個大圖片分享平臺。這個app中,反射再次造成了一個大問題。
image.png
??上圖中,花費了660ms來調用com.photobucket.api.client.jersey.UserClient構造器。通過進一步觀察"冰狀圖",我們發現原因在于反射。如下圖所示:
image.png
??注意,
getGenericInterfaces()
返回的直接實現類的接口類型,這里調用了5次,而且花費了81ms,當然,表面上看起來也許不太像,但是兩者使用這個方法導致了600ms的延時。接下來看一看到底是什么原因導致了花費這么多時間。這個庫允許開發人員配置帶有注解的REST客戶端,可問題是,程序在編譯時是不處理注解的,而是在運行時解析和創建REST客戶端(在反射的幫助下)。在性能上來看,這是災難性的。
微型基準測試
??我們創建了一個測試用例來測試反射有多慢。
??我們在Android項目的Activity中執行重復操作10000次:
Class<?> clazz = android.app.Activity.class;
for (int i = 0; i < 10000; i++) {
clazz.getFields();
}
??我們還創建了兩個測試來創建對象(一個空類 DummyItem)去測試反射引起的嚴重性。如下:
try {
for (int i = 0; i < 1_000_000; i++) {
DummyItem.class.newInstance();
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
??以下是測試結果(在真實的個人設備上進行測試,求一個真實的結果)
image.png
??很明顯,在Android中使用反射是極其緩慢的。使用反射(1332ms, 6384ms, 2891ms),不使用反射(312ms, 358ms, 774ms)。有趣的是,在一個更優質的設備Android 5.0 ART上使用反射竟然比在一個不是那么好的Android 4.1 Dalvik 的設備使用反射更慢。僅僅在6.0上減輕了這方法的負載,但是這個問題仍然是非常繁重的。
更實際的例子
??ActiveAndroid是一個使用了反射的庫。讓我們看一看他對應用的影響。
這是一個 Scribd app:
image.png
??Myntra也有同樣的問題:
image.png
??如你所見,這個庫需要1s多去初始化。然而,用戶期望一個app的啟動時間大概是2s.
??總而言之,反射在Android中是非常的慢。為了你能給用戶一個美好的體驗,我們又如下建議:
??理解使用反射(或使用反射的庫)時會遇到什么問題,尤其是不要使用反射類型適配器去序列化或反序列化Java對象。