日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

小谈JVM及JIT

發(fā)布時(shí)間:2024/4/17 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小谈JVM及JIT 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


http://www.deepinmind.com/jvm/2014/06/28/a-little-bit-on-jvm-and-jit.html

你或許也知道,正是JVM( Java Virtusal Machine,Java虛擬機(jī))使得Java成為遵循“一次編寫(xiě),處處運(yùn)行”的范例。JVM包括如下核心組件:

  • 持久代及方法區(qū)
  • JIT編譯器
  • 代碼緩存

堆是你的應(yīng)用程序代碼中new操作符分配內(nèi)存的地方。棧存儲(chǔ)的是你在某個(gè)方法作用域內(nèi)要進(jìn)行賦值的那些本地變量。有一點(diǎn)需要注意的是,方法作用域內(nèi)所定義的變量在方法結(jié)束后將會(huì)被刪除。比如說(shuō),一個(gè)String變量在方法內(nèi)被賦值了,它的作用域是本地作用域,那么它將會(huì)被存儲(chǔ)到棧里,而給它所賦的值則是存儲(chǔ)在堆中。

持久代空間是用來(lái)存儲(chǔ)類及方法的數(shù)據(jù)以及應(yīng)用程序中定義的靜態(tài)變量。方法區(qū)其實(shí)就是持久代空間中的一塊區(qū)域,它將會(huì)存儲(chǔ)所有的方法,字段,常量池的詳細(xì)數(shù)據(jù)。

JIT編譯器和代碼緩存密不可分。JVM核心會(huì)在運(yùn)行時(shí)將Java字節(jié)碼解釋成匯編代碼。這個(gè)解釋的過(guò)程是非常緩慢的,因?yàn)槊看螆?zhí)行你的應(yīng)用程序的代碼時(shí)都需要將字節(jié)碼轉(zhuǎn)化成機(jī)器代碼。這就是JIT編譯器發(fā)揮作用的地方了,它會(huì)將方法編譯好然后存儲(chǔ)到代碼緩存中。

JIT編譯器會(huì)在運(yùn)行時(shí)分析應(yīng)用程序的代碼,來(lái)識(shí)別出哪些方法可以歸類為熱方法。在這里熱方法意味著代碼段會(huì)被頻繁地訪問(wèn)。JIT編譯器給每個(gè)方法都分配一個(gè)計(jì)數(shù)器,以便統(tǒng)計(jì)它們的使用頻率。當(dāng)計(jì)數(shù)器達(dá)到預(yù)定義的閾值時(shí),這個(gè)方法會(huì)被JIT編譯器編譯成對(duì)應(yīng)的匯編代碼,然后存儲(chǔ)到代碼緩存中?,F(xiàn)在,當(dāng)JIT需要再調(diào)用這些已經(jīng)被編譯好并存儲(chǔ)到代碼緩存中的方法時(shí),它不用再去解釋執(zhí)行了,而是可以使用代碼緩存中已編譯好的匯編代碼。這能提升你的應(yīng)用程序的執(zhí)行效率,因?yàn)槭褂镁幾g好的代碼要比運(yùn)行時(shí)去解釋要快得多。

當(dāng)提及JIT編譯器時(shí),由于缺少相關(guān)的文檔,有兩個(gè)主要的因素我們大多數(shù)人可能都不太了解。它們分別是:

  • Client
  • Server

默認(rèn)使用哪個(gè)編譯器取決于對(duì)應(yīng)程序運(yùn)行的機(jī)器的體系結(jié)構(gòu)以及JVM的版本(32位還是64位的)。我們來(lái)看下它們分別有什么作用。

客戶端編譯器在應(yīng)用啟動(dòng)的時(shí)候就會(huì)將你的字節(jié)碼編譯成匯編代碼。這間接意味著會(huì)增加你的應(yīng)用程序的啟動(dòng)時(shí)間。不過(guò)它最大的缺點(diǎn)在于你的代碼緩存可能很快就會(huì)用光你的內(nèi)存。很多優(yōu)化只有當(dāng)你的程序運(yùn)行了一段時(shí)間才能夠進(jìn)行。不過(guò)由于客戶端編譯器已經(jīng)占用了代碼緩存的空間,你可能沒(méi)有地方去存儲(chǔ)這些優(yōu)化后的匯編代碼了。這就是服務(wù)端編譯器要?jiǎng)俪龅牡胤健?/p>

服務(wù)端編譯器不像客戶端編譯器那樣,它不會(huì)在應(yīng)用啟動(dòng)的時(shí)候就編譯代碼。它會(huì)讓?xiě)?yīng)用程序的代碼運(yùn)行一段時(shí)間(這也被稱為預(yù)熱階段),然后它才會(huì)開(kāi)始將字節(jié)碼編譯成匯編代碼,最終將它們存儲(chǔ)到代碼緩存里。

我的下一篇文章將會(huì)討論如何可以將客戶端及服務(wù)端編譯給結(jié)合起來(lái),同時(shí)還將介紹幾個(gè)很少用到的JVM參數(shù),但它們對(duì)提升應(yīng)用的性能至關(guān)重要。



==============Java HotSpot VM中的JIT編譯

http://ifeve.com/hotspot-jit/

本文是Java HotSpot VM and just-in-time(JIT) compilation系列的第一篇。

Java HotSpot虛擬機(jī)是Oracle收購(gòu)Sun時(shí)獲得的,JVM和開(kāi)源的OpenJDK都是以此虛擬機(jī)為基礎(chǔ)發(fā)展的。如同其它虛擬機(jī),HotSpot虛擬機(jī)為字節(jié)碼提供了一個(gè)運(yùn)行時(shí)環(huán)境。實(shí)際上,它主要會(huì)做這三件事情:

  • 執(zhí)行方法所請(qǐng)求的指令和運(yùn)算。
  • 定位、加載和驗(yàn)證新的類型(即類加載)。
  • 管理應(yīng)用內(nèi)存。

最后兩點(diǎn)都是各自領(lǐng)域的大話題,所以這篇文章中只關(guān)注代碼執(zhí)行。

JIT編譯

Java HotSpot是一個(gè)混合模式的虛擬機(jī),也就是說(shuō)它既可以解釋字節(jié)碼,又可以將代碼編譯為本地機(jī)器碼以更快的執(zhí)行。通過(guò)配置-XX:+PrintCompilation參數(shù),你可以在log文件中看到方法被JIT編譯時(shí)的信息。JIT編譯發(fā)生在運(yùn)行時(shí) —— 方法經(jīng)過(guò)多次運(yùn)行之后。到方法需要使用到的時(shí)候,HotSpot VM會(huì)決定如何優(yōu)化這些代碼。

如果你好奇JIT編譯帶來(lái)的性能提升,可以使用-Djava.compiler=none將其關(guān)掉然后運(yùn)行基準(zhǔn)測(cè)試程序來(lái)看看它們的差別。

Java HotSpot虛擬機(jī)可以運(yùn)行在兩種模式下:client或者server。你可以在JVM啟動(dòng)時(shí)通過(guò)配置-client或者-server選項(xiàng)來(lái)選擇其中一種。兩種模式都有各自的適用場(chǎng)景,本文中,我們只會(huì)涉及到server模式。

兩種模式最主要的區(qū)別是server模式下會(huì)進(jìn)行更激進(jìn)的優(yōu)化 —— 這些優(yōu)化是建立在一些并不永遠(yuǎn)為真的假設(shè)之上。一個(gè)簡(jiǎn)單的保護(hù)條件(guard condition)會(huì)驗(yàn)證這些假設(shè)是否成立,以確保優(yōu)化總是正確的。如果假設(shè)不成立,Java HotSpot虛擬機(jī)將會(huì)撤銷所做的優(yōu)化并退回到解釋模式。也就是說(shuō)Java HotSpot虛擬機(jī)總是會(huì)先檢查優(yōu)化是否仍然有效,不會(huì)因?yàn)榧僭O(shè)不再成立而表現(xiàn)出錯(cuò)誤的行為。

在server模式下,Java HotSpot虛擬機(jī)會(huì)默認(rèn)在解釋模式下運(yùn)行方法10000次才會(huì)觸發(fā)JIT編譯。可以通過(guò)虛擬機(jī)參數(shù)-XX:CompileThreshold來(lái)調(diào)整這個(gè)值。比如-XX:CompileThreshold=5000會(huì)讓觸發(fā)JIT編譯的方法運(yùn)行次數(shù)減少一半。(譯者注:有關(guān)JIT觸發(fā)條件可參考《深入理解Java虛擬機(jī)》第十一章以及《Java Performance》第三章HotSpot VM JIT Compilers小節(jié))

這可能會(huì)誘使新手將編譯閾值調(diào)整到一個(gè)非常低的值。但要抵擋住這個(gè)誘惑,因?yàn)檫@樣可能會(huì)降低虛擬機(jī)性能,優(yōu)化后減少的方法執(zhí)行時(shí)間還不足以抵消花在JIT編譯上的時(shí)間。

當(dāng)Java HotSpot虛擬機(jī)能為JIT編譯收集到足夠多的統(tǒng)計(jì)信息時(shí),性能會(huì)最好。當(dāng)你降低編譯閾值時(shí),Java HotSpot虛擬機(jī)可能會(huì)在非熱點(diǎn)代碼的編譯中花費(fèi)較多時(shí)間。有些優(yōu)化只有在收集到足夠多的統(tǒng)計(jì)信息時(shí)才會(huì)進(jìn)行,所以降低編譯閾值可能導(dǎo)致優(yōu)化效果不佳。

另外一方面,很多開(kāi)發(fā)者想讓一些重要方法在編譯模式下盡快獲得更好的性能。

解決此問(wèn)題一般是在進(jìn)程啟動(dòng)后,對(duì)代碼進(jìn)行預(yù)熱以使它們被強(qiáng)制編譯。對(duì)于像訂單系統(tǒng)或者交易系統(tǒng)來(lái)說(shuō),重要的是要確保預(yù)熱不會(huì)產(chǎn)生真實(shí)的訂單。

Java HotSpot虛擬機(jī)提供了很多參數(shù)來(lái)輸出JIT的編譯信息。最常用的就是前文提到的PrintCompilation,也還有一些其它參數(shù)。

接下來(lái)我們將使用PrintCompilation來(lái)觀察Java HotSpot虛擬機(jī)在運(yùn)行時(shí)編譯方法的成效。但先有必要說(shuō)一下用于計(jì)時(shí)的System.nanoTime()方法。

計(jì)時(shí)方法

Java為我們提供了兩個(gè)主要的獲取時(shí)間值的方法:currentTimeMillis()和nanoTime().前者對(duì)應(yīng)于我們?cè)趯?shí)體世界中看到的時(shí)間(所謂的鐘表時(shí)間),它的精度能滿足大多數(shù)情況,但不適用于低延遲的應(yīng)用。

納秒計(jì)時(shí)器擁有更高的精度。這種計(jì)時(shí)器度量時(shí)間的間隔極短。1納秒是光在光纖中移動(dòng)20CM所需的時(shí)間,相比之下,光通過(guò)光纖從倫敦傳送到紐約大約需要27.5毫秒。

因?yàn)榧{秒級(jí)的時(shí)間戳精度太高,使用不當(dāng)就會(huì)產(chǎn)生較大誤差,因此使用時(shí)需要注意。

如,currentTimeMillis()能很好的在機(jī)器間同步,可以用于測(cè)量網(wǎng)絡(luò)延遲,但nanoTime()不能跨機(jī)器使用。

接下來(lái)將上面的理論付諸實(shí)踐,來(lái)看一個(gè)很簡(jiǎn)單(但極其強(qiáng)大)的JIT編譯技術(shù)。

方法內(nèi)聯(lián)

方法內(nèi)聯(lián)是編譯器優(yōu)化的關(guān)鍵手段之一。方法內(nèi)聯(lián)就是把方法的代碼“復(fù)制”到發(fā)起調(diào)用的方法里,以消除方法調(diào)用。這個(gè)功能相當(dāng)重要,因?yàn)檎{(diào)用一個(gè)小方法可能比執(zhí)行該小方法的方法體耗時(shí)還多。

JIT編譯器可以進(jìn)行漸進(jìn)內(nèi)聯(lián),開(kāi)始時(shí)內(nèi)聯(lián)簡(jiǎn)單的方法,如果可以進(jìn)行其它優(yōu)化時(shí),就接著優(yōu)化內(nèi)聯(lián)后的較大的代碼塊。

Listing1,Listing1A以及Listing1B是個(gè)簡(jiǎn)單的測(cè)試,將直接操作字段和通過(guò)getter/setter方法做了對(duì)比。如果簡(jiǎn)單的getters和setters方法沒(méi)有使用內(nèi)聯(lián)的話,那調(diào)用它們的代價(jià)是相當(dāng)大的,因?yàn)榉椒ㄕ{(diào)用比直接操作字段代價(jià)更高。

Listing1:

查看源代碼 打印幫助
01public class Main {
02????private static double timeTestRun(String desc, int runs,
03????????Callable<Double> callable) throws Exception {
04????????long start = System.nanoTime();
05????????callable.call();
06????????long time = System.nanoTime() - start;
07????????return (double) time / runs;
08????}
09?
10????// Housekeeping method to provide nice uptime values for us
11????private static long uptime() {
12????????return ManagementFactory.getRuntimeMXBean().getUptime() + 15;
13????// fudge factor
14????}
15?
16????public static void main(String... args) throws Exception {
17????????int iterations = 0;
18????????for (int i : new int[]
19????????????{ 100, 1000, 5000, 9000, 10000, 11000, 13000, 20000, 100000} ) {
20????????????final int runs = i - iterations;
21????????????iterations += runs;
22?
23????????????// NOTE: We return double (sum of values) from our test cases to
24????????????// prevent aggressive JIT compilation from eliminating the loop in
25????????????// unrealistic ways
26????????????Callable<Double> directCall = new DFACaller(runs);
27????????????Callable<Double> viaGetSet = new GetSetCaller(runs);
28?
29????????????double time1 = timeTestRun("public fields", runs, directCall);
30????????????double time2 = timeTestRun("getter/setter fields", runs, viaGetSet);
31?
32????????????System.out.printf("%7d %,7d\t\tfield access=%.1f ns, getter/setter=%.1f ns%n",
33????????????????uptime(), iterations, time1, time2);
34????????????// added to improve readability of the output
35????????????Thread.sleep(100);
36????????}
37????}
38}

Listing1A:

查看源代碼 打印幫助
01public class DFACaller implements Callable<Double>{
02????private final int runs;
03?
04????public DFACaller(int runs_) {
05????????runs = runs_;
06????}
07?
08????@Override
09????public Double call() {
10????????DirectFieldAccess direct = new DirectFieldAccess();
11????????double sum = 0;
12????????for (int i = 0; i < runs; i++) {
13????????????direct.one++;
14????????????sum += direct.one;
15????????}
16????????return sum;
17????}
18}
19?
20public class DirectFieldAccess {
21????int one;
22}

Listing1B:

查看源代碼 打印幫助
01public class GetSetCaller implements Callable<Double> {
02????private final int runs;
03?
04????public GetSetCaller(int runs_) {
05????????runs = runs_;
06????}
07?
08????@Override
09????public Double call() {
10????????ViaGetSet getSet = new ViaGetSet();
11????????double sum = 0;
12????????for (int i = 0; i < runs; i++) {
13????????????getSet.setOne(getSet.getOne() + 1);
14????????????sum += getSet.getOne();
15????????}
16????????return sum;
17????}
18}
19?
20public class ViaGetSet {
21????private int one;
22?
23????public int getOne() {
24????????return one;
25????}
26?
27????public void setOne(int one) {
28????????this.one = one;
29????}
30}

如果使用java -cp. -XX:PrintCompilation Main 運(yùn)行測(cè)試用例,就能看到性能上的差異(見(jiàn)Listing2)。

Listing2

31 1 java.lang.String::hashCode (67 bytes) 36 100 field access=1970.0 ns, getter/setter=1790.0 ns 39 2 sun.nio.cs.UTF_8$Encoder::encode (361 bytes) 42 3 java.lang.String::indexOf (87 bytes) 141 1,000 field access=16.7 ns, getter/setter=67.8 ns 245 5,000 field access=16.8 ns, getter/setter=72.8 ns 245 4 ViaGetSet::getOne (5 bytes) 348 9,000 field access=16.0 ns, getter/setter=65.3 ns 450 5 ViaGetSet::setOne (6 bytes) 450 10,000 field access=16.0 ns, getter/setter=199.0 ns 553 6 Main$1::call (51 bytes) 554 7 Main$2::call (51 bytes) 556 8 java.lang.String::charAt (33 bytes) 556 11,000 field access=1263.0 ns, getter/setter=1253.0 ns 658 13,000 field access=5.5 ns, getter/setter=1.5 ns 760 20,000 field access=0.7 ns, getter/setter=0.7 ns 862 100,000 field access=0.7 ns, getter/setter=0.7 ns

這些是什么意思?Listing2中的第一列是程序啟動(dòng)到語(yǔ)句執(zhí)行時(shí)所經(jīng)過(guò)的毫秒數(shù),第二列是方法ID(編譯后的方法)或遍歷次數(shù)。

注意:測(cè)試中沒(méi)有直接使用String和UTF_8類,但它們?nèi)匀怀霈F(xiàn)在編譯的輸出中,這是因?yàn)槠脚_(tái)使用了它們。

從Listing2中的第二行可以發(fā)現(xiàn),直接訪問(wèn)字段和通過(guò)getter/setter都是比較慢的,這是因?yàn)榈谝淮芜\(yùn)行時(shí)包含了類加載的時(shí)間,下一行就比較快了,盡管此時(shí)還沒(méi)有任何代碼被編譯。

另外要注意下面幾點(diǎn):

  • 在遍歷1000和5000次時(shí),直接操作字段比使用getter/setter方法快,因?yàn)間etter 和setter還沒(méi)有內(nèi)聯(lián)或優(yōu)化。即便如此,它們都還相當(dāng)?shù)乜臁?
  • 在遍歷9000次時(shí),getter方法被優(yōu)化了(因?yàn)槊看窝h(huán)中調(diào)用了兩次),使性能有小許提高。
  • 在遍歷10000次時(shí),setter方法也被優(yōu)化了,因?yàn)樾枰~外花費(fèi)時(shí)間去優(yōu)化,所以執(zhí)行速度降下來(lái)了。
  • 最終,兩個(gè)測(cè)試類都被優(yōu)化了:
    • DFACaller直接操作字段,GetSetCaller使用getter和setter方法。此時(shí)它們不僅剛被優(yōu)化,還被內(nèi)聯(lián)了。
    • 從下一次的遍歷中可以看到,測(cè)試用例的執(zhí)行時(shí)間仍不是最快的。
  • 在13000次遍歷之后,兩種字段訪問(wèn)方式的性能都和最后更長(zhǎng)時(shí)間測(cè)試的結(jié)果一樣好,我們已經(jīng)達(dá)到了性能的穩(wěn)定狀態(tài)。

需要特別注意的是,直接訪問(wèn)字段和通過(guò)getter/setter訪問(wèn)在穩(wěn)定狀態(tài)下的性能是基本一致的,因?yàn)榉椒ㄒ呀?jīng)被內(nèi)聯(lián)到GetSetCaller中,也就是說(shuō)在viaGetSet中所做的事情和directCall中完全一樣。

JIT編譯是在后臺(tái)進(jìn)行的。每次可用的優(yōu)化手段可能隨機(jī)器的不同而不同,甚至,同個(gè)程序的多次運(yùn)行期間也可能不一樣。

總結(jié)

這篇文章中,我所描述的只是JIT編譯的冰山一角,尤其是沒(méi)有提到如何寫(xiě)出好的基準(zhǔn)測(cè)試以及如何使用統(tǒng)計(jì)信息以確保不會(huì)被平臺(tái)的動(dòng)態(tài)性所愚弄。

這里使用的基準(zhǔn)測(cè)試非常簡(jiǎn)單,不適合做為真實(shí)的基準(zhǔn)測(cè)試。在第二部分,我計(jì)劃向您展示一個(gè)真實(shí)的基準(zhǔn)測(cè)試并繼續(xù)深入JIT編譯的過(guò)程。

與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的小谈JVM及JIT的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 少妇福利视频 | 久热这里只有精品在线 | 亚洲91网 | 精品欧美视频 | 亚洲女人天堂成人av在线 | 香蕉视频免费看 | 国产美女无遮挡永久免费观看 | 窝窝视频在线观看 | free黑人多人性派对hd | 开心综合网 | 精品成人网 | 亚州av在线播放 | 麻豆精品国产传媒av | 国产成人综合网 | 色偷偷av男人的天堂 | 91久久伊人 | 国产欧美精品在线 | 天堂综合在线 | 18禁一区二区 | 美日韩成人av | 国产乱子伦视频一区二区三区 | 国产三级福利 | 日韩精品免费一区二区在线观看 | 国产真实乱在线更新 | 人妻久久久一区二区三区 | 日本阿v视频 | 2022精品国偷自产免费观看 | 久久五月天婷婷 | 337p粉嫩大胆色噜噜噜 | 国产欧美日韩精品一区二区三区 | 欧美国产日韩视频 | 久久六六 | 日本一区二区高清视频 | 欧美天堂网站 | 国产午夜视频在线观看 | 牛牛av| 亚洲精品不卡 | 日本午夜在线 | xxx69美国| 中文字幕av高清片 | 素人av在线 | 国产美女黄网站 | 久久久蜜桃一区二区 | 黄色视屏软件 | 精品人妻一区二区乱码 | 亚洲一区91 | 日本一区二区三区在线免费观看 | 国产欧美亚洲精品 | 久久久久亚洲av无码专区首jn | 丝袜制服影音先锋 | 国产欧洲亚洲 | 男男h黄动漫啪啪无遮挡软件 | 亚洲清纯唯美 | 国产精品一区二区无线 | 水蜜桃色314在线观看 | 国产亚洲av片在线观看18女人 | av不卡在线观看 | 污污的视频在线免费观看 | 日本wwww色 | 狂野欧美性猛交xxxx巴西 | 少妇丰满尤物大尺度写真 | 亚洲国产成人91精品 | 日本三区视频 | 91污网站| 动漫裸体无遮挡 | 亚洲精品在线视频 | 黄色aa毛片| 可以在线看的av | 日本一级理论片在线大全 | 在线观看欧美一区 | 亚洲人成网站999久久久综合 | 久久亚洲免费视频 | 神秘马戏团在线观看免费高清中文 | 亚洲欧美影院 | 日本人视频69式jzzij | 东北毛片 | 亚洲AV成人无码久久精品巨臀 | 日本性视频网站 | 天天5g天天爽免费观看 | 播播开心激情网 | 中国新婚夫妻性猛交 | 成人国产精品 | 色播99| 欧美野外猛男的大粗鳮 | 欧美精品1| 日本亚洲免费 | 美日韩精品 | 国产乱子伦一区二区 | 亚洲最大的av网站 | 日韩在线资源 | 免费福利视频在线观看 | 亚洲最大视频网 | 日韩夜夜高潮夜夜爽无码 | av不卡在线免费观看 | 波多野结衣先锋影音 | 国产精品久久久久免费 | 久久综合久色欧美综合狠狠 | 国产一区二区三区免费 | 丰满少妇xoxoxo视频 |