久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      JAVA虛擬機(jī)(JVM)詳細(xì)介紹(七)——JVM優(yōu)化

      JAVA虛擬機(jī)(JVM)詳細(xì)介紹(七)——JVM優(yōu)化

      還以這個圖為例,從.java到.class是編譯過程,從.class到機(jī)器碼是解釋過程。下面對其進(jìn)行分別優(yōu)化。在優(yōu)化過程中,對編譯階段的優(yōu)化主要是對前端編譯器的優(yōu)化,在運(yùn)行階段的優(yōu)化,主要是對即時編譯器的優(yōu)化。

      JAVA虛擬機(jī)(JVM)詳細(xì)介紹(七)——JVM優(yōu)化

      編譯器優(yōu)化

      編譯過程

      JAVA虛擬機(jī)(JVM)詳細(xì)介紹(七)——JVM優(yōu)化

      以上為javac的編譯過程圖,以下為javac編譯過程的主體代碼。

      JAVA虛擬機(jī)(JVM)詳細(xì)介紹(七)——JVM優(yōu)化

      下面對其步驟進(jìn)行詳細(xì)解讀
      1、解析與填充符號表

      詞法分析

      將源代碼的字符流轉(zhuǎn)變?yōu)闃?biāo)記(Token)集合,標(biāo)記是編譯過程中的最小元素,如a,=,b,int。

      語法分析

      根據(jù)Token序列構(gòu)造抽象語法樹。以后編譯器基本不會再對源碼文件進(jìn)行操作了,后續(xù)的操作都是建立在抽象語法樹上。抽象語法樹是一種用來描述程序代碼語法結(jié)構(gòu)的樹形表示方式,節(jié)點(diǎn)代表代碼中的一個語法結(jié)構(gòu),例如修飾符,返回值等。

      填充符號表

      符號表是由一組符號地址和符號信息構(gòu)成的表格,用于編譯的不同階段。如在語義分析中,用于語義檢查和產(chǎn)生中間代碼;在目標(biāo)代碼生成階段,用于地址分配的依據(jù)。

      2、注解處理器
      這部分是插入式注解處理器在編譯期間對注解進(jìn)行處理的過程。其可以對語法樹進(jìn)行修改,一旦進(jìn)行了修改,編譯器將回到上面的第一步進(jìn)行重新處理,每一次循環(huán)稱為一個Round,也就是上圖中的回環(huán)過程。

      3、語義分析與字節(jié)碼生成
      在經(jīng)過語法分析后,生成的語法樹是一個結(jié)構(gòu)正確的源程序的抽象,但無法保證源程序是符合邏輯的。語義分析的任務(wù)是對結(jié)構(gòu)上正確的源程序進(jìn)行上下文有關(guān)性質(zhì)的審查。比如下面代碼中的錯誤只能在語義分析階段檢查出來。

      boolean a=false; char b=2; int c=a+b

      此階段包括如下4個步驟:

      標(biāo)注檢查

      變量使用前是否已被聲明、變量與賦值之間的數(shù)據(jù)類型是否能夠匹配等。還有一個常量折疊,即把a(bǔ)=1+2變?yōu)閍=3。所以在代碼中的a=1+2和a=3并不會增加程序運(yùn)行期cpu指令的運(yùn)算量。

      數(shù)據(jù)及控制流分析

      檢查程序局部變量在使用前是否有賦值,方法的每條路徑是否都有返回值,是否所有的受查異常都被正確處理了等問題。在類加載時也有一個數(shù)據(jù)及控制流分析,其目的基本是一致的,但校驗(yàn)的范圍不同,有些校驗(yàn)項(xiàng)只有在編譯期或運(yùn)行期才能運(yùn)行。

      解語法糖

      語法糖是在計算機(jī)語言中添加某種語法,其對語言的功能沒有影響,但是能提高程序的可讀性。語法糖包括泛型,自動拆裝箱等。虛擬機(jī)運(yùn)行時不支持這些語法,它們在編譯階段還原回基礎(chǔ)語法結(jié)構(gòu)。這個過程稱為解語法糖。

      字節(jié)碼生成

      將之前步驟生成的信息(語法樹、符號表)轉(zhuǎn)化成字節(jié)碼寫到磁盤中,然后添加和轉(zhuǎn)換了少量的代碼。如把字符串的加操作替換為StringBuffer或StringBuilder的append()操作。

      至此,Class文件生成了。

      語法糖

      語法糖是java中添加某種語法,對語言的功能沒有影響,但是可以增加程序的可讀性。包括泛型、內(nèi)部類、枚舉類等。

      1、泛型與類型擦除
      泛型可用于類、接口和方法的創(chuàng)建中,用于對放入集合元素的類型的約束。泛型只在程序源碼中存在,在編譯階段有解語法糖的步驟,所以在.Class文件中,已經(jīng)變?yōu)榱嗽瓉淼脑愋土?。這個過程叫做類型擦除。
      泛型擦除前:

      public static void main(String[] args){     Map<String,String> map=new HashMap<>();     map.put("姓名","小明");     map.put("性別","男");     sout(map.get("姓名"));     sout(map.get("性別")); }

      泛型擦除后:

      public static void main(String[] args){     Map map=new HashMap();     map.put("姓名","小明");     map.put("性別","男");     sout((String)map.get("姓名"));     sout((String)map.get("性別")); }

      所以ArrayList和ArrayList在運(yùn)行期時是同一個類。

      2、自動拆裝箱、循環(huán)遍歷
      這些是java中使用最多的語法糖。編譯前:

      public static void main(String[] args){       List<Integer> list=Arrays.asList(1,2,3,4);       int sum=0;       for(int i:list){               sum +=i;       }       System.out.println(sum); }

      編譯后:

      public static void main(String[] args){       List list=Arrays.asList(new Integer[] {                 Integer.valueOf(1),                 Integer.valueOf(2),                 Integer.valueOf(3),                 Integer.valueOf(4)});       int sum=0;       for(Iterator localIterator=list.iterator();localIterator.hasNext();){                    int i=((Integer)localIterator.next()).intValue();                    sum +=i;       }       System.out.println(sum); }

      可見,自動拆裝箱在編譯后被轉(zhuǎn)化為了對應(yīng)的包裝和還原方法,如Integer.valueOf()和Integer.intValue()。
      遍歷循環(huán)則把代碼還原為了迭代器的實(shí)現(xiàn)。

      3、條件編譯
      根據(jù)布爾常量值的真假,編譯器會把分支中不成立的代碼塊消除掉。

      public static void main(String[] args){       if(true){             sout("block 1");       }else{            sout("block 2");      } }

      編譯后,代碼變?yōu)椋?/p>

      public static void main(String[] args){      sout("block 1"); }

      運(yùn)行期優(yōu)化

      一般情況下,我們將.java編譯成.class,.class再解釋成機(jī)器碼。但是也有特殊的情況。有些代碼調(diào)用比較頻繁,比如某個方法或代碼塊的運(yùn)行特別頻繁,為了提高程序的執(zhí)行效率,在運(yùn)行時,虛擬機(jī)會把這個代碼直接編譯成機(jī)器碼,并進(jìn)行各種層次的優(yōu)化。這樣的代碼稱為熱點(diǎn)代碼。完成這個任務(wù)的編譯器被稱為即時編譯器。但是其并不是虛擬機(jī)必需的部分。

      JAVA虛擬機(jī)(JVM)詳細(xì)介紹(七)——JVM優(yōu)化

      即時編譯器的概述

      (1)為什么虛擬機(jī)要使用解釋器和編譯器并存的架構(gòu)?

      虛擬機(jī)里包含著解釋器和編譯器。當(dāng)程序需要迅速啟動和執(zhí)行的時候,解釋器可以首先發(fā)揮作用,省去編譯的時間,立即執(zhí)行。在程序運(yùn)行后,隨著時間的推移,編譯器逐漸發(fā)揮作用,把越來越多的代碼編譯成本地代碼之后,可以獲取更高的執(zhí)行效率。

      當(dāng)程序運(yùn)行環(huán)境中內(nèi)存資源限制較大,可以使用解釋執(zhí)行節(jié)約內(nèi)存,反之可以使用編譯來提升效率。

      (2)為什么虛擬機(jī)要實(shí)現(xiàn)兩個不同的即時編譯器?

      虛擬機(jī)中內(nèi)置了兩個即時編譯器,分別為Client Compiler和Server Compiler,又稱為C1和C2。

      默認(rèn)只使用其中的一個,至于選擇哪個,取決于虛擬機(jī)會根據(jù)自身版本和宿主機(jī)器的硬件性能自動選擇運(yùn)行模式。用戶也可以使用“-client”、“-server”進(jìn)行指定。

      (3)程序何時使用解釋器執(zhí)行?何時使用編譯器執(zhí)行?

      虛擬機(jī)有一個分層編譯策略。

      第0層:程序解釋執(zhí)行,解釋器不開啟性能監(jiān)控功能,可觸發(fā)第1層編譯

      第1層:也稱為C1編譯,將字節(jié)碼編譯為本地代碼,進(jìn)行簡單、可靠的優(yōu)化,如有必要將加入性能監(jiān)控的邏輯。

      第2層:也稱為C2編譯,將字節(jié)碼編譯為本地代碼,但是會啟用一些編譯耗時較長的優(yōu)化,甚至?xí)鶕?jù)性能監(jiān)控信息進(jìn)行一些不可靠的激進(jìn)優(yōu)化。

      (4)哪些程序代碼會被編譯為本地代碼?如何編譯為本地代碼?

      熱點(diǎn)代碼包括如下兩類,其均把整個方法作為編譯對象。

      a、被多次調(diào)用的方法

      b、被多次執(zhí)行的循環(huán)體

      熱點(diǎn)探測是用來判斷一段代碼是否為熱點(diǎn)代碼,其方式有兩種:

      a、基于采樣

      b、基于計數(shù)器。HotSpot使用的是這種。它為每個方法準(zhǔn)備了兩類計數(shù)器:統(tǒng)計方法被調(diào)用次數(shù)的方法調(diào)用計數(shù)器和統(tǒng)計一個方法中循環(huán)體代碼執(zhí)行次數(shù)的回邊計數(shù)器。

      (5)如何從外部觀察及時編譯器的編譯過程和編譯結(jié)果?

      可以使用 -xx:+PrintCompilation 查看哪些方法被即時編譯器編譯了。

      優(yōu)化技術(shù)有哪些?

      虛擬機(jī)的即時編譯器在生成代碼時,采用了如下的代碼優(yōu)化技術(shù)。

      (1)公共子表達(dá)式消除

      如果一個表達(dá)式E已經(jīng)計算過了,那如果再次出現(xiàn)E時就不會再對它進(jìn)行計算。比如:

      int d=(a*b)*12+c+(c+b*a)

      如果這段代碼交給javac編譯器,則不會進(jìn)行任何優(yōu)化。如果交給即時編譯器,會被進(jìn)行如下步驟的優(yōu)化:

      第一步:消除公共子表達(dá)式

      int d=E*12+c+(c+E)

      第二步:代數(shù)化簡:

      int d=E*13+c*2

      (2)數(shù)組邊界檢查消除

      數(shù)組邊界檢查是什么?
      如果有一個數(shù)組foo[],在java語言中訪問數(shù)組元素foo[i]的時候,系統(tǒng)將會自動進(jìn)行上下界的范圍檢查,檢查i是否滿足0≤i≤foo.length這個條件。

      那怎么進(jìn)行消除呢?
      a、把運(yùn)行期檢查提到編譯期完成。如foo[3],只要在編譯期根據(jù)數(shù)據(jù)流分析來確定foo.length的值,并判斷下標(biāo)“3”沒有越界,執(zhí)行的時候就不用判斷了。
      b、隱式異常處理。這種思路通常用于空指針檢查和算符運(yùn)算中除數(shù)為零的情況。

      if(foo!=null){   return foo.value; }else{   throw new NullPointException(); }

      被隱式異常處理優(yōu)化后,變?yōu)槿缦麓a:

      try{   return foo.value; }catch(segment_fault){   uncommon_trap(); }

      除了數(shù)組邊界檢查消除,還有自動裝箱消除、安全點(diǎn)消除、消除反射等。

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

      把目標(biāo)方法的代碼“復(fù)制”到發(fā)起調(diào)用的方法之中,避免發(fā)生真實(shí)的方法調(diào)用。

      public int add(int x1, int x2, int x3, int x4) {           return add1(x1, x2) + add1(x3, x4);    }    public int add1(int x1, int x2) {           return x1 + x2;       }

      運(yùn)行一段時間后JVM會把a(bǔ)dd1方法去掉,并把代碼翻譯成:

      public int add(int x1, int x2, int x3, int x4) {           return x1 + x2 + x3 + x4;   }

      (4)逃逸分析

      當(dāng)一個對象在方法中被定義后,它可能被外部方法所引用,比如作為調(diào)用參數(shù)傳遞到其它方法中,這稱為方法逃逸。同理,如果被外部線程訪問到,它就稱為線程逃逸。

      對變量進(jìn)行相應(yīng)分析就叫做逃逸分析。如果能證明別的方法或線程無法通過任何途徑訪問到這個對象,則可以為這個變量進(jìn)行一些優(yōu)化。

      優(yōu)化的手段有棧上分配、同步消除、標(biāo)量替換等。以同步消除為例,如果逃逸分析能夠確定一個變量不會逃逸出線程,即無法被其它線程訪問到,那對這個變量實(shí)施的同步措施就可以消除掉了。

      以上內(nèi)容便是關(guān)于JAVA虛擬機(jī)中JVM優(yōu)化的全部介紹,

      贊(1)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號