欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
實(shí)時(shí) Java,第 2 部分: 比較編譯技術(shù)

Mark Stoodley (mstoodle@ca.ibm.com), 咨詢(xún)軟件開(kāi)發(fā)人員, IBM Toronto Lab
Kenneth Ma (kenma@ca.ibm.com), 軟件開(kāi)發(fā)人員, IBM Toronto Lab
Marius Lut (lut@ca.ibm.com), 軟件開(kāi)發(fā)人員, IBM Toronto Lab

2007 年 5 月 16 日

本文是關(guān)于實(shí)時(shí) Java™ 的 系列文章(共 5 部分)的第二篇,考察了 Java 語(yǔ)言的本地代碼編譯所涉及的一些問(wèn)題。單獨使用動(dòng)態(tài)(即時(shí))編譯或靜態(tài)(提前)編譯都不能滿(mǎn)足所有 Java 應用程序的需求。作者在各種執行環(huán)境中對這兩種編譯技術(shù)進(jìn)行了比較,對二者如何相互補充進(jìn)行了展示。

Java應用程序的性能經(jīng)常成為開(kāi)發(fā)社區中的討論熱點(diǎn)。因為該語(yǔ)言的設計初衷是使用解釋的方式支持應用程序的可移植性目標,早期 Java運行時(shí)所提供的性能級別遠低于 C 和 C++之類(lèi)的編譯語(yǔ)言。盡管這些語(yǔ)言可以提供更高的性能,但是生成的代碼只能在有限的幾種系統上執行。在過(guò)去的十年中,Java運行時(shí)供應商開(kāi)發(fā)了一些復雜的動(dòng)態(tài)編譯器,通常稱(chēng)作即時(shí)(Just-in-time,JIT)編譯器。程序運行時(shí),JIT編譯器選擇將最頻繁執行的方法編譯成本地代碼。運行時(shí)才進(jìn)行本地代碼編譯而不是在程序運行前進(jìn)行編譯(用 C 或 C++編寫(xiě)的程序正好屬于后一情形),保證了可移植性的需求。有些 JIT編譯器甚至不使用解釋程序就能編譯所有的代碼,但是這些編譯器仍然通過(guò)在程序執行時(shí)進(jìn)行一些操作來(lái)保持 Java 應用程序的可移植性。

由于動(dòng)態(tài)編譯技術(shù)的多項改進(jìn),在很多應用程序中,現代的 JIT 編譯器可以產(chǎn)生與 C 或 C++靜態(tài)編譯相當的應用程序性能。但是,仍然有很多軟件開(kāi)發(fā)人員認為 —— 基于經(jīng)驗或者傳聞 ——動(dòng)態(tài)編譯可能?chē)乐馗蓴_程序操作,因為編譯器必須與應用程序共享 CPU。一些開(kāi)發(fā)人員強烈呼吁對 Java代碼進(jìn)行靜態(tài)編譯,并且堅信那樣可以解決性能問(wèn)題。對于某些應用程序和執行環(huán)境而言,這種觀(guān)點(diǎn)是正確的,靜態(tài)編譯可以極大地提高 Java性能,或者說(shuō)它是惟一的實(shí)用選擇。但是,靜態(tài)地編譯 Java 應用程序在獲得高性能的同時(shí)也帶來(lái)了很多復雜性。一般的 Java開(kāi)發(fā)人員可能并沒(méi)有充分地感受到 JIT 動(dòng)態(tài)編譯器的優(yōu)點(diǎn)。

本文考察了 Java語(yǔ)言靜態(tài)編譯和動(dòng)態(tài)編譯所涉及的一些問(wèn)題,重點(diǎn)介紹了實(shí)時(shí) (RT) 系統。簡(jiǎn)要描述了 Java 語(yǔ)言解釋程序的操作原理并說(shuō)明了現代 JIT編譯器執行本地代碼編譯的優(yōu)缺點(diǎn)。介紹了 IBM® 在 WebSphere® Real Time 中發(fā)布的 AOT編譯技術(shù)和它的一些優(yōu)缺點(diǎn)。然后比較了這兩種編譯策略并指出了幾種比較適合使用 AOT編譯的應用程序領(lǐng)域和執行環(huán)境。要點(diǎn)在于這兩種編譯技術(shù)并不互斥:即使在使用這兩種技術(shù)最為有效的各種應用程序中,它們也分別存在一些影響應用程序的優(yōu)缺點(diǎn)。

執行 Java 程序

Java 程序最初是通過(guò) Java SDK 的 javac程序編譯成本地的與平臺無(wú)關(guān)的格式(類(lèi)文件)??蓪⒋烁袷娇醋?Java 平臺,因為它定義了執行 Java 程序所需的所有信息。Java程序執行引擎,也稱(chēng)作 Java 運行時(shí)環(huán)境(JRE),包含了為特定的本地平臺實(shí)現 Java 平臺的虛擬機。例如,基于 Linux® 的Intel x86 平臺、Sun Solaris 平臺和 AIX® 操作系統上運行的 IBM System p™ 平臺,每個(gè)平臺都擁有一個(gè)JRE。這些 JRE 實(shí)現實(shí)現了所有的本地支持,從而可以正確執行為 Java 平臺編寫(xiě)的程序。

事實(shí)上,操作數堆棧的大小有實(shí)際限制,但是編程人員極少編寫(xiě)超出該限制的方法。JVM 提供了安全性檢查,對那些創(chuàng )建出此類(lèi)方法的編程人員進(jìn)行通知。

Java 平臺程序表示的一個(gè)重要部分是字節碼序列,它描述了 Java類(lèi)中每個(gè)方法所執行的操作。字節碼使用一個(gè)理論上無(wú)限大的操作數堆棧來(lái)描述計算。這個(gè)基于堆棧的程序表示提供了平臺無(wú)關(guān)性,因為它不依賴(lài)任何特定本地平臺的 CPU 中可用寄存器的數目??稍诓僮鲾刀褩I蠄绦械牟僮鞯亩x都獨立于所有本地處理器的指令集。Java虛擬機(JVM)規范定義了這些字節碼的執行(參見(jiàn) 參考資料)。執行 Java 程序時(shí),用于任何特定本地平臺的任何 JRE 都必須遵守 JVM 規范中列出的規則。

因為基于堆棧的本地平臺很少(Intel X87 浮點(diǎn)數協(xié)處理器是一個(gè)明顯的例外),所以大多數本地平臺不能直接執行 Java 字節碼。為了解決這個(gè)問(wèn)題,早期的 JRE 通過(guò)解釋 字節碼來(lái)執行 Java 程序。即 JVM 在一個(gè)循環(huán)中重復操作:

  1. 獲取待執行的下一個(gè)字節碼。
  2. 解碼。
  3. 從操作數堆棧獲取所需的操作數。
  4. 按照 JVM 規范執行操作。
  5. 將結果寫(xiě)回堆棧。

這種方法的優(yōu)點(diǎn)是其簡(jiǎn)單性:JRE 開(kāi)發(fā)人員只需編寫(xiě)代碼來(lái)處理每種字節碼即可。并且因為用于描述操作的字節碼少于 255 個(gè),所以實(shí)現的成本比較低。當然,缺點(diǎn)是性能:這是一個(gè)早期造成很多人對 Java 平臺不滿(mǎn)的問(wèn)題,盡管擁有很多其他優(yōu)點(diǎn)。

解決與 C 或 C++ 之類(lèi)的語(yǔ)言之間的性能差距意味著(zhù),使用不會(huì )犧牲可移植性的方式開(kāi)發(fā)用于 Java 平臺的本地代碼編譯。





回頁(yè)首


編譯 Java 代碼

盡管傳聞中 Java 編程的 “一次編寫(xiě),隨處運行”的口號可能并非在所有情況下都嚴格成立,但是對于大量的應用程序來(lái)說(shuō)情況確實(shí)如此。另一方面,本地編譯本質(zhì)上是特定于平臺的。那么 Java平臺如何在不犧牲平臺無(wú)關(guān)性的情況下實(shí)現本地編譯的性能?答案就是使用 JIT 編譯器進(jìn)行動(dòng)態(tài)編譯,這種方法已經(jīng)使用了十年(參見(jiàn)圖 1):


圖 1. JIT 編譯器

使用 JIT 編譯器時(shí),Java程序按每次編譯一個(gè)方法的形式進(jìn)行編譯,因為它們在本地處理器指令中執行以獲得更高的性能。此過(guò)程將生成方法的一個(gè)內部表示,該表示與字節碼不同但是其級別要高于目標處理器的本地指令。(IBM JIT編譯器使用一個(gè)表達式樹(shù)序列表示方法的操作。)編譯器執行一系列優(yōu)化以提高質(zhì)量和效率,最后執行一個(gè)代碼生成步驟將優(yōu)化后的內部表示轉換成目標處理器的本地指令。生成的代碼依賴(lài)運行時(shí)環(huán)境來(lái)執行一些活動(dòng),比如確保類(lèi)型轉換的合法性或者對不能在代碼中直接執行的某些類(lèi)型的對象進(jìn)行分配。JIT編譯器操作的編譯線(xiàn)程與應用程序線(xiàn)程是分開(kāi)的,因此應用程序不需要等待編譯的執行。

圖 1 中還描述了用于觀(guān)察執行程序行為的分析框架,通過(guò)周期性地對線(xiàn)程取樣找出頻繁執行的方法。該框架還為專(zhuān)門(mén)進(jìn)行分析的方法提供了工具,用來(lái)存儲程序的此次執行中可能不會(huì )改變的動(dòng)態(tài)值。

因為這個(gè) JIT 編譯過(guò)程在程序執行時(shí)發(fā)生,所以能夠保持平臺無(wú)關(guān)性:發(fā)布的仍然是中立的 Java 平臺代碼。C 和 C++ 之類(lèi)的語(yǔ)言缺乏這種優(yōu)點(diǎn),因為它們在程序執行前進(jìn)行本地編譯;發(fā)布給(本地平臺)執行環(huán)境的是本地代碼。

挑戰

盡管通過(guò) JIT 編譯保持了平臺無(wú)關(guān)性,但是付出了一定代價(jià)。因為在程序執行時(shí)進(jìn)行編譯,所以編譯代碼的時(shí)間將計入程序的執行時(shí)間。任何編寫(xiě)過(guò)大型 C 或 C++ 程序的人都知道,編譯過(guò)程往往較慢。

為了克服這個(gè)缺點(diǎn),現代的 JIT編譯器使用了下面兩種方法的任意一種(某些情況下同時(shí)使用了這兩種方法)。第一種方法是:編譯所有的代碼,但是不執行任何耗時(shí)多的分析和轉換,因此可以快速生成代碼。由于生成代碼的速度很快,因此盡管可以明顯觀(guān)察到編譯帶來(lái)的開(kāi)銷(xiāo),但是這很容易就被反復執行本地代碼所帶來(lái)的性能改善所掩蓋。第二種方法是:將編譯資源只分配給少量的頻繁執行的方法(通常稱(chēng)作 方法)。低編譯開(kāi)銷(xiāo)更容易被反復執行熱代碼帶來(lái)的性能優(yōu)勢掩蓋。很多應用程序只執行少量的熱方法,因此這種方法有效地實(shí)現了編譯性能成本的最小化。

動(dòng)態(tài)編譯器的一個(gè)主要的復雜性在于權衡了解編譯代碼的預期獲益使方法的執行對整個(gè)程序的性能起多大作用。一個(gè)極端的例子是,程序執行后,您非常清楚哪些方法對于這個(gè)特定的執行的性能貢獻最大,但是編譯這些方法毫無(wú)用處,因為程序已經(jīng)完成。而在另一個(gè)極端,程序執行前無(wú)法得知哪些方法重要,但是每種方法的潛在受益都最大化了。大多數動(dòng)態(tài)編譯器的操作介于這兩個(gè)極端之間,方法是權衡了解方法預期獲益的重要程度。

Java語(yǔ)言需要動(dòng)態(tài)加載類(lèi)這一事實(shí)對 Java編譯器的設計有著(zhù)重要的影響。如果待編譯代碼引用的其他類(lèi)還沒(méi)有加載怎么辦?比如一個(gè)方法需要讀取某個(gè)尚未加載的類(lèi)的靜態(tài)字段值。Java語(yǔ)言要求第一次執行類(lèi)引用時(shí)加載這個(gè)類(lèi)并將其解析到當前的 JVM中。直到第一次執行時(shí)才解析引用,這意味著(zhù)沒(méi)有地址可供從中加載該靜態(tài)字段。編譯器如何處理這種可能性?編譯器生成一些代碼,用于在沒(méi)有加載類(lèi)時(shí)加載并解析類(lèi)。類(lèi)一旦被解析,就會(huì )以一種線(xiàn)程安全的方式修改原始代碼位置以便直接訪(fǎng)問(wèn)靜態(tài)字段的地址,因為此時(shí)已獲知該地址。

IBMJIT編譯器中進(jìn)行了大量的努力以便使用安全而有效率的代碼補丁技術(shù),因此在解析類(lèi)之后,執行的本地代碼只加載字段的值,就像編譯時(shí)已經(jīng)解析了字段一樣。另外一種方法是生成一些代碼,用于在查明字段的位置以前一直檢查是否已經(jīng)解析字段,然后加載該值。對于那些由未解析變成已解析并被頻繁訪(fǎng)問(wèn)的字段來(lái)說(shuō),這種簡(jiǎn)單的過(guò)程可能帶來(lái)嚴重的性能問(wèn)題。

動(dòng)態(tài)編譯的優(yōu)點(diǎn)

動(dòng)態(tài)地編譯 Java 程序有一些重要的優(yōu)點(diǎn),甚至能夠比靜態(tài)編譯語(yǔ)言更好地生成代碼,現代的 JIT 編譯器常常向生成的代碼中插入掛鉤以收集有關(guān)程序行為的信息,以便如果要選擇方法進(jìn)行重編譯,就可以更好地優(yōu)化動(dòng)態(tài)行為。

關(guān)于此方法的一個(gè)很好的例子是收集一個(gè)特定 arraycopy 操作的長(cháng)度。如果發(fā)現每次執行操作時(shí)該長(cháng)度基本不變,則可以為最頻繁使用的 arraycopy長(cháng)度生成專(zhuān)門(mén)的代碼,或者可以調用調整為該長(cháng)度的代碼序列。由于內存系統和指令集設計的特性,用于復制內存的最佳通用例程的執行速度通常比用于復制特定長(cháng)度的代碼慢。例如,復制 8個(gè)字節的對齊的數據可能需要一到兩條指令直接復制,相比之下,使用可以處理任意字節數和任意對齊方式的一般復制循環(huán)可能需要 10 條指令來(lái)復制同樣的8個(gè)字節。但是,即使此類(lèi)專(zhuān)門(mén)的代碼是為某個(gè)特定的長(cháng)度生成的,生成的代碼也必須正確地執行其他長(cháng)度的復制。生成代碼只是為了使常見(jiàn)長(cháng)度的操作執行得更快,因此平均下來(lái),性能得到了改進(jìn)。此類(lèi)優(yōu)化對大多數靜態(tài)編譯語(yǔ)言通常不實(shí)用,因為所有可能的執行中長(cháng)度恒定的操作比一個(gè)特定程序執行中長(cháng)度恒定的操作要少得多。

此類(lèi)優(yōu)化的另一個(gè)重要的例子是基于類(lèi)層次結構的優(yōu)化。例如,一個(gè)虛方法調用需要查看接收方對象的類(lèi)調用,以便找出哪個(gè)實(shí)際目標實(shí)現了接收方對象的虛方法。研究表明:大多數虛調用只有一個(gè)目標對應于所有的接收方對象,而 JIT編譯器可以為直接調用生成比虛調用更有效率的代碼。通過(guò)分析代碼編譯后類(lèi)層次結構的狀態(tài),JIT編譯器可以為虛調用找到一個(gè)目標方法,并且生成直接調用目標方法的代碼而不是執行較慢的虛調用。當然,如果類(lèi)層次結構發(fā)生變化,并且出現另外的目標方法,則 JIT編譯器可以更正最初生成的代碼以便執行虛調用。在實(shí)踐中,很少需要作出這些更正。另外,由于可能需要作出此類(lèi)更正,因此靜態(tài)地執行這種優(yōu)化非常麻煩。

因為動(dòng)態(tài)編譯器通常只是集中編譯少量的熱方法,所以可以執行更主動(dòng)的分析來(lái)生成更好的代碼,使編譯的回報更高。事實(shí)上,大部分現代的 JIT編譯器也支持重編譯被認為是熱方法的方法??梢允褂渺o態(tài)編譯器(不太強調編譯時(shí)間)中常見(jiàn)的非常主動(dòng)的優(yōu)化來(lái)分析和轉換這些頻繁執行的方法,以便生成更好的代碼并獲得更高的性能。

這些改進(jìn)及其他一些類(lèi)似的改進(jìn)所產(chǎn)生的綜合效果是:對于大量的 Java 應用程序來(lái)說(shuō),動(dòng)態(tài)編譯已經(jīng)彌補了與 C 和 C++ 之類(lèi)語(yǔ)言的靜態(tài)本地編譯性能之間的差距,在某些情況下,甚至超過(guò)了后者的性能。

缺點(diǎn)

但是,動(dòng)態(tài)編譯確實(shí)具有一些缺點(diǎn),這些缺點(diǎn)使它在某些情況下算不上一個(gè)理想的解決方案。例如,因為識別頻繁執行的方法以及編譯這些方法需要時(shí)間,所以應用程序通常要經(jīng)歷一個(gè)準備過(guò)程,在這個(gè)過(guò)程中性能無(wú)法達到其最高值。在這個(gè)準備過(guò)程中出現性能問(wèn)題有幾個(gè)原因。首先,大量的初始編譯可能直接影響應用程序的啟動(dòng)時(shí)間。不僅這些編譯延遲了應用程序達到穩定狀態(tài)的時(shí)間(想像 Web服務(wù)器經(jīng)歷一個(gè)初始階段后才能夠執行實(shí)際有用的工作),而且在準備階段中頻繁執行的方法可能對應用程序的穩定狀態(tài)的性能所起的作用也不大。如果 JIT編譯會(huì )延遲啟動(dòng)又不能顯著(zhù)改善應用程序的長(cháng)期性能,則執行這種編譯就非常浪費。雖然所有的現代 JVM都執行調優(yōu)來(lái)減輕啟動(dòng)延遲,但是并非在所有情況下都能夠完全解決這個(gè)問(wèn)題。

其次,有些應用程序完全不能忍受動(dòng)態(tài)編譯帶來(lái)的延遲。如 GUI 接口之類(lèi)交互式應用程序就是這樣的例子。在這種情況下,編譯活動(dòng)可能對用戶(hù)使用造成不利影響,同時(shí)又不能顯著(zhù)地改善應用程序的性能。

最后,用于實(shí)時(shí)環(huán)境并具有嚴格的任務(wù)時(shí)限的應用程序可能無(wú)法忍受編譯的不確定性性能影響或動(dòng)態(tài)編譯器本身的內存開(kāi)銷(xiāo)。

因此,雖然 JIT 編譯技術(shù)已經(jīng)能夠提供與靜態(tài)語(yǔ)言性能相當(甚至更好)的性能水平,但是動(dòng)態(tài)編譯并不適合于某些應用程序。在這些情況下,Java 代碼的提前(Ahead-of-time,AOT)編譯可能是合適的解決方案。





回頁(yè)首


AOT Java 編譯

大致說(shuō)來(lái),Java 語(yǔ)言本地編譯應該是為傳統語(yǔ)言(如 C++ 或 Fortran)而開(kāi)發(fā)的編譯技術(shù)的一個(gè)簡(jiǎn)單應用。不幸的是,Java語(yǔ)言本身的動(dòng)態(tài)特性帶來(lái)了額外的復雜性,影響了 Java 程序靜態(tài)編譯代碼的質(zhì)量。但是基本思想仍然是相同的:在程序執行前生成 Java方法的本地代碼,以便在程序運行時(shí)直接使用本地代碼。目的在于避免 JIT 編譯器的運行時(shí)性能消耗或內存消耗,或者避免解釋程序的早期性能開(kāi)銷(xiāo)。

挑戰

動(dòng)態(tài)類(lèi)加載是動(dòng)態(tài) JIT 編譯器面臨的一個(gè)挑戰,也是 AOT編譯的一個(gè)更重要的問(wèn)題。只有在執行代碼引用類(lèi)的時(shí)候才加載該類(lèi)。因為是在程序執行前進(jìn)行 AOT編譯的,所以編譯器無(wú)法預測加載了哪些類(lèi)。就是說(shuō)編譯器無(wú)法獲知任何靜態(tài)字段的地址、任何對象的任何實(shí)例字段的偏移量或任何調用的實(shí)際目標,甚至對直接調用(非虛調用)也是如此。在執行代碼時(shí),如果證明對任何這類(lèi)信息的預測是錯誤的,這意味著(zhù)代碼是錯誤的并且還犧牲了 Java 的一致性。

因為代碼可以在任何環(huán)境中執行,所以類(lèi)文件可能與代碼編譯時(shí)不同。例如,一個(gè) JVM實(shí)例可能從磁盤(pán)的某個(gè)特定位置加載類(lèi),而后面一個(gè)實(shí)例可能從不同的位置甚至網(wǎng)絡(luò )加載該類(lèi)。設想一個(gè)正在進(jìn)行 bug修復的開(kāi)發(fā)環(huán)境:類(lèi)文件的內容可能隨不同的應用程序的執行而變化。此外,Java 代碼可能在程序執行前根本不存在:比如 Java反射服務(wù)通常在運行時(shí)生成新類(lèi)來(lái)支持程序的行為。

缺少關(guān)于靜態(tài)、字段、類(lèi)和方法的信息意味著(zhù)嚴重限制了 Java 編譯器中優(yōu)化框架的大部分功能。內聯(lián) 可能是靜態(tài)或動(dòng)態(tài)編譯器應用的最重要的優(yōu)化,但是由于編譯器無(wú)法獲知調用的目標方法,因此無(wú)法再使用這種優(yōu)化。

內聯(lián)

內聯(lián)是一種用于在運行時(shí)生成代碼避免程序開(kāi)始和結束時(shí)開(kāi)銷(xiāo)的技術(shù),方法是將函數的調用代碼插入到調用方的函數中。但是內聯(lián)最大的益處可能是優(yōu)化方可見(jiàn)的代碼的范圍擴大了,從而能夠生成更高質(zhì)量的代碼。下面是一個(gè)內聯(lián)前的代碼示例:

int foo() { int x=2, y=3; return bar(x,y); }                                    final int bar(int a, int b) { return a+b; }                                    

如果編譯器可以證明這個(gè) bar 就是 foo() 中調用的那個(gè)方法,則 bar 中的代碼可以取代 foo() 中對 bar() 的調用。這時(shí),bar() 方法是 final 類(lèi)型,因此肯定是 foo() 中調用的那個(gè)方法。甚至在一些虛調用例子中,動(dòng)態(tài) JIT 編譯器通常能夠推測性地內聯(lián)目標方法的代碼,并且在絕大多數情況下能夠正確使用。編譯器將生成以下代碼:

int foo() { int x=2, y=3; return x+y; } 

在這個(gè)例子中,簡(jiǎn)化前名為值傳播 的優(yōu)化可以生成直接返回 5 的代碼。如果不使用內聯(lián),則不能執行這種優(yōu)化,產(chǎn)生的性能就會(huì )低很多。如果沒(méi)有解析 bar() 方法(例如靜態(tài)編譯),則不能執行這種優(yōu)化,而代碼必須執行虛調用。運行時(shí),實(shí)際調用的可能是另外一個(gè)執行兩個(gè)數字相乘而不是相加的 bar 方法。所以不能在 Java 程序的靜態(tài)編譯期間直接使用內聯(lián)。

AOT代碼因此必須在沒(méi)有解析每個(gè)靜態(tài)、字段、類(lèi)和方法引用的情況下生成。執行時(shí),每個(gè)這些引用必須利用當前運行時(shí)環(huán)境的正確值進(jìn)行更新。這個(gè)過(guò)程可能直接影響第一次執行的性能,因為在第一次執行時(shí)將解析所有引用。當然,后續執行將從修補代碼中獲益,從而可以更直接地引用實(shí)例、靜態(tài)字段或方法目標。

另外,為 Java 方法生成的本地代碼通常需要使用僅在單個(gè) JVM 實(shí)例中使用的值。例如,代碼必須調用 JVM運行時(shí)中的某些運行時(shí)例程來(lái)執行特定操作,如查找未解析的方法或分配內存。這些運行時(shí)例程的地址可能在每次將 JVM 加載到內存時(shí)變化。因此 AOT編譯代碼需要綁定到 JVM 的當前執行環(huán)境中,然后才能執行。其他的例子有字符串的地址和常量池入口的內部位置。

在 WebSphere Real Time 中,AOT 本地代碼編譯通過(guò) jxeinajar 工具(參見(jiàn)圖 2)來(lái)執行。該工具對 JAR 文件中所有類(lèi)的所有方法應用本地代碼編譯,也可以選擇性地對需要的方法應用本地代碼編譯。結果被存儲到名為 Java eXEcutable (JXE) 的內部格式中,但是也可輕松地存儲到任意的持久性容器中。


圖 2. jxeinajar

您可能認為對所有的代碼進(jìn)行靜態(tài)編譯是最好的方法,因為可以在運行時(shí)執行最大數量的本地代碼。但是此處可以作出一些權衡。編譯的方法越多,代碼占用的內存就越多。編譯后的本地代碼大概比字節碼大 10 倍:本地代碼本身的密度比字節碼小,而且必須包含代碼的附加元數據,以便將代碼綁定到 JVM中,并且在出現異?;蛘埱蠖褩8檿r(shí)正確執行代碼。構成普通 Java 應用程序的 JAR文件通常包含許多很少執行的方法。編譯這些方法會(huì )消耗內存卻沒(méi)有什么預期收益。相關(guān)的內存消耗包括以下過(guò)程:將代碼存儲到磁盤(pán)上、從磁盤(pán)取出代碼并裝入JVM,以及將代碼綁定到 JVM。除非多次執行代碼,否則這些代價(jià)不能由本地代碼相對解釋的性能優(yōu)勢來(lái)彌補。

跟大小問(wèn)題相違背的一個(gè)事實(shí)是:在編譯過(guò)的方法和解釋過(guò)的方法之間進(jìn)行的調用(即編譯過(guò)的方法調用解釋過(guò)的方法,或者相反)可能比這兩類(lèi)方法各自?xún)炔恐g進(jìn)行的調用所需的開(kāi)銷(xiāo)大。動(dòng)態(tài)編譯器通過(guò)最終編譯所有由 JIT編譯代碼頻繁調用的那些解釋過(guò)的方法來(lái)減少這項開(kāi)銷(xiāo),但是如果不使用動(dòng)態(tài)編譯器,則這項開(kāi)銷(xiāo)就不可避免。因此如果是選擇性地編譯方法,則必須謹慎操作以使從已編譯方法到未編譯方法的轉換最小化。為了在所有可能的執行中都避免這個(gè)問(wèn)題而選擇正確的方法會(huì )非常困難。

優(yōu)點(diǎn)

雖然 AOT 編譯代碼具有上述的缺點(diǎn)和挑戰,但是提前編譯 Java 程序可以提高性能,尤其是在不能將動(dòng)態(tài)編譯器作為有效解決方案的環(huán)境中。

可以通過(guò)謹慎地使用 AOT 編譯代碼加快應用程序啟動(dòng),因為雖然這種代碼通常比 JIT 編譯代碼慢,但是卻比解釋代碼快很多倍。此外,因為加載和綁定AOT編譯代碼的時(shí)間通常比檢測和動(dòng)態(tài)編譯一個(gè)重要方法的時(shí)間少,所以能夠在程序執行的早期達到那樣的性能。類(lèi)似地,交互式應用程序可以很快地從本地代碼中獲益,無(wú)需使用引起較差響應能力的動(dòng)態(tài)編譯。

RT 應用程序也能從 AOT編譯代碼中獲得重要的收益:更具確定性的性能超過(guò)了解釋的性能。WebSphere Real Time 使用的動(dòng)態(tài) JIT 編譯器針對在 RT系統中的使用進(jìn)行了專(zhuān)門(mén)的調整。使編譯線(xiàn)程以低于 RT 任務(wù)的優(yōu)先級操作,并且作出了調整以避免生成帶有嚴重的不確定性性能影響的代碼。但是,在一些RT 環(huán)境中,出現 JIT 編譯器是不可接受的。此類(lèi)環(huán)境通常需要最嚴格的時(shí)限管理控制。在這些例子中,AOT編譯代碼可以提供比解釋過(guò)的代碼更好的原始性能,又不會(huì )影響現有的確定性。消除 JIT 編譯線(xiàn)程甚至消除了啟動(dòng)更高優(yōu)先級 RT任務(wù)時(shí)發(fā)生的線(xiàn)程搶占所帶來(lái)的性能影響。





回頁(yè)首


優(yōu)缺點(diǎn)統計

動(dòng)態(tài)(JIT)編譯器支持平臺中立性,并通過(guò)利用應用程序執行的動(dòng)態(tài)行為和關(guān)于加載的類(lèi)及其層次結構的信息來(lái)生成高質(zhì)量的代碼。但是 JIT編譯器具有一個(gè)有限的編譯時(shí)預算,而且會(huì )影響程序的運行時(shí)性能。另一方面,靜態(tài)(AOT)編譯器則犧牲了平臺無(wú)關(guān)性和代碼質(zhì)量,因為它們不能利用程序的動(dòng)態(tài)行為,也不具有關(guān)于加載的類(lèi)或類(lèi)層次結構的信息。AOT 編譯擁有有效無(wú)限制的編譯時(shí)預算,因為 AOT編譯時(shí)間不會(huì )影響運行時(shí)性能,但是在實(shí)踐中開(kāi)發(fā)人員不會(huì )長(cháng)期等待靜態(tài)編譯步驟的完成。

表 1 總結了本文討論的 Java 語(yǔ)言動(dòng)態(tài)和靜態(tài)編譯器的一些特性:


表 1. 比較編譯技術(shù)
動(dòng)態(tài) (JIT)靜態(tài) (AOT)
平臺無(wú)關(guān)性 無(wú)
代碼質(zhì)量 優(yōu)秀 良好
利用動(dòng)態(tài)行為
類(lèi)和層次結構的知識 無(wú)
編譯時(shí)間 有限制,有運行時(shí)成本 限制很少,無(wú)運行時(shí)成本
運行時(shí)性能影響 無(wú)
編譯方式 需要謹慎編譯,由 JIT 處理 需要謹慎編譯,由開(kāi)發(fā)人員處理

兩種技術(shù)都需要謹慎選擇編譯的方法以實(shí)現最高的性能。對動(dòng)態(tài)編譯器而言,編譯器自身作出決策,而對于靜態(tài)編譯器,由開(kāi)發(fā)人員作出選擇。讓 JIT 編譯器選擇編譯的方法是不是優(yōu)點(diǎn)很難說(shuō),取決于編譯器在給定情形中推斷能力的好壞。在大多數情況下,我們認為這是一種優(yōu)點(diǎn)。

因為它們可以最好地優(yōu)化運行中的程序,所以 JIT 編譯器在提供穩定狀態(tài)性能方面更勝一籌,而這一點(diǎn)在大量的生產(chǎn) Java系統中最為重要。靜態(tài)編譯可以產(chǎn)生最佳的交互式性能,因為沒(méi)有運行時(shí)編譯行為來(lái)影響用戶(hù)預期的響應時(shí)間。通過(guò)調整動(dòng)態(tài)編譯器可以在某種程度上解決啟動(dòng)和確定性性能問(wèn)題,但是靜態(tài)編譯在需要時(shí)可提供最快的啟動(dòng)速度和最高級別的確定性。表 2 在四種不同的執行環(huán)境中對這兩種編譯技術(shù)進(jìn)行了比較:


表 2. 使用這些技術(shù)的最佳環(huán)境
動(dòng)態(tài) (JIT)靜態(tài) (AOT)
啟動(dòng)性能 可調整,但不是最好 最好
穩定狀態(tài)性能 最好
交互式性能 一般 良好
確定性性能 可調整,但不是最好 最好

圖 3 展示了啟動(dòng)性能和穩定狀態(tài)性能的總體趨勢:


圖 3. AOT 和 JIT 的性能對比

使用 JIT 編譯器的初始階段性能很低,因為要首先解釋方法。隨著(zhù)編譯方法的增多及 JIT執行編譯所需時(shí)間的縮短,性能曲線(xiàn)逐漸升高最后達到性能峰值。另一方面,AOT 編譯代碼啟動(dòng)時(shí)的性能比解釋的性能高很多,但是無(wú)法達到 JIT編譯器所能達到的最高性能。將靜態(tài)代碼綁定到 JVM 實(shí)例中會(huì )產(chǎn)生一些開(kāi)銷(xiāo),因此開(kāi)始時(shí)的性能比穩定狀態(tài)的性能值低,但是能夠比使用 JIT編譯器更快地達到穩定狀態(tài)的性能水平。

沒(méi)有一種本地代碼編譯技術(shù)能夠適合所有的 Java執行環(huán)境。某種技術(shù)所擅長(cháng)的通常正是其他技術(shù)的弱項。出于這個(gè)原因,需要同時(shí)使用這兩種編譯技術(shù)以滿(mǎn)足 Java應用程序開(kāi)發(fā)人員的要求。事實(shí)上,可以結合使用靜態(tài)和動(dòng)態(tài)編譯以便提供最大可能的性能提升 —— 但是必須具備平臺無(wú)關(guān)性,它是 Java語(yǔ)言的主要賣(mài)點(diǎn),因此不成問(wèn)題。





回頁(yè)首


結束語(yǔ)

本文探討了 Java 語(yǔ)言本地代碼編譯的問(wèn)題,主要介紹了 JIT 編譯器形式的動(dòng)態(tài)編譯和靜態(tài) AOT 編譯,比較了二者的優(yōu)缺點(diǎn)。

雖然動(dòng)態(tài)編譯器在過(guò)去的十年里實(shí)現了極大的成熟,使大量的各種 Java 應用程序可以趕上或超過(guò)靜態(tài)編譯語(yǔ)言(如 C++ 或Fortran)所能夠達到的性能。但是動(dòng)態(tài)編譯在某些類(lèi)型的應用程序和執行環(huán)境中仍然不太合適。雖然 AOT編譯號稱(chēng)動(dòng)態(tài)編譯缺點(diǎn)的萬(wàn)能解決方案,但是由于 Java 語(yǔ)言本身的動(dòng)態(tài)特性,它也面臨著(zhù)提供本地編譯全部潛能的挑戰。

這兩種技術(shù)都不能解決 Java 執行環(huán)境中本地代碼編譯的所有需求,但是反過(guò)來(lái)又可以在最有效的地方作為工具使用。這兩種技術(shù)可以相互補充。能夠恰當地使用這兩種編譯模型的運行時(shí)系統可以使很大范圍內的應用程序開(kāi)發(fā)環(huán)境中的開(kāi)發(fā)人員和用戶(hù)受益。



參考資料

學(xué)習

獲得產(chǎn)品和技術(shù)
  • WebSphere Real Time:WebSphere Real Time 利用了標準的 Java 技術(shù)并且沒(méi)有損失確定性,使應用程序依賴(lài)于精確的響應時(shí)間。

  • Real-time Java 技術(shù):訪(fǎng)問(wèn)作者的 IBM alphaWorks 研究站點(diǎn),查找用于實(shí)時(shí) Java 的先進(jìn)技術(shù)。


討論


作者簡(jiǎn)介

Mark Stoodley 在 2001 年從多倫多大學(xué)獲得計算機工程的博士學(xué)位,并于 2002 年加入 IBM 多倫多實(shí)驗室,研究 Java JIT 編譯技術(shù)。從 2005 年起,通過(guò)采用現有的 JIT 編譯器并在實(shí)時(shí)環(huán)境中進(jìn)行操作,他開(kāi)始為 IBM WebSphere Real Time 開(kāi)發(fā) JIT 技術(shù)。他現在是 Java 編譯控制團隊的團隊負責人,從事在本地代碼的執行環(huán)境中提高本地代碼編譯效率的工作。工作以外,他喜歡收拾自己的家。


Kenneth Ma 2003 年在 Waterloo 大學(xué)畢業(yè),獲得了電子工程應用科學(xué)的學(xué)士學(xué)位,此后不久他成為 IBM 的專(zhuān)職開(kāi)發(fā)人員。先前在 IBM 實(shí)習期間,他從事 IBM 的 WebSphere 平臺上的 iSeries 工具開(kāi)發(fā)工作。Kenneth 現在是 IBM Testarossa JIT Compiler 團隊的一員。在過(guò)去兩年里,他一直致力于實(shí)現和改進(jìn) IBM J9 Java 虛擬機的 AOT 編譯技術(shù),最近從事將該技術(shù)遷移到 Java SE 環(huán)境的工作。


Marius Lut 在羅馬尼亞的 Timisoara 工藝大學(xué)獲得了自動(dòng)化和計算機工程學(xué)位。他在 1998 年加入 IBM 多倫多實(shí)驗室。從那以后他從事 z/OS 的 IBM HPJ 靜態(tài)編譯器、IBM Sovereign JIT 編譯器的開(kāi)發(fā)工作,最近三年開(kāi)發(fā)了 IBM Testarossa JIT 技術(shù)。他擁有 J2SE、J2ME 編譯器、嵌入式系統的軟件開(kāi)發(fā)與設計、RT 環(huán)境、大型機和基于 Intel 處理器的系統等領(lǐng)域的開(kāi)發(fā)經(jīng)驗。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
計算機世界網(wǎng)-Java性能的優(yōu)化(上)
編碼準則與Java編譯器
從高級源碼到機器碼的過(guò)程,反射DLL加載卸載
什么是 Angular Ahead-of-time (AOT) compilation
Java性能的優(yōu)化(二)
詳解Android jit
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久