<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # JVM運行時數據區 圖示一: ![](https://img.kancloud.cn/19/ee/19ee6ef38e84d53da384c2de8a68f209_1635x1055.png) 圖示二: ![](https://img.kancloud.cn/57/eb/57eb048854b71175d2d9cde925928022_994x712.png) 圖示三: ![](https://img.kancloud.cn/94/df/94df9c2d2b1e95722c98f072b8f78761_888x492.png) 圖示四: ![](https://img.kancloud.cn/e9/29/e929e38722ad69367679fe5c4f26e0d3_1657x859.png) Java代碼被編譯器編譯成字節碼之后,JVM開辟一片內存空間(也叫運行時數據區),通過類加載器加到到運行時數據區來存儲程序執行期間需要用到的數據和相關信息,在這個數據區中,它由以下幾部分組成: 1、程序計數器:線程私有,記錄著當前線程所執行的字節碼的行號指示器,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。 2、虛擬機棧:線程私有,棧中存放著棧幀,每個棧幀分別對應一個被調用的方法,方法的調用過程對應棧幀在虛擬機中入棧到出棧的過程。每個棧幀中存儲有局部變量表、操作數棧、動態鏈接、方法出口等。 3、本地方法棧:線程私有,和虛擬機棧基本一致,但是為執行native方法而服務的。 4、堆:線程共有,是JVM所管理的內存中最大的一塊,用來存儲對象實例和數組,在JVM中只有一個堆,但可以處于物理上不連續的內存空間中。由于現在垃圾收集器通常采用分代回收算法,因此堆可以細分為永久世代(permanent)、成熟世代(tenured)、年輕世代(young)。 5、方法區:線程共有,用來存放已經加載的類信息、常量、靜態變量以及即時編譯器編譯后的代碼等。 6、運行時常量池:是方法區的一部分,用于存儲編譯期生成的各種字面量和符號引用。 有一點需要注意的是,當局部變量重新賦值時,基本數據類型的數據本身是不會改變的。并不是在內存中改變字面量內容,而是重新在棧中尋找已存在的相同的數據,若棧中不存在,則重新開辟內存存新數據,并且把要重新賦值的局部變量的引用指向新數據所在地址。 # GC垃圾回收 1、JVM中的棧記錄了線程的方法調用,每個線程擁有一個棧,在線程運行的過程中,如果有新的方法調用,那么該線程對應的棧就會增加一個棧幀,棧幀中存儲有該方法的參數、局部變量、返回地址。Java的參數和局部變量只能是基本數據類型或者對象引用,因此棧幀中僅存儲基本數據類型和引用,而對象引用所引用的對象存儲在堆中。方法調用結束時,該棧幀會被刪除,參數和局部變量占用的空間也被刪除,但對象引用所引用的對象還在堆中。 2、Java對象都存儲在堆中,為線程共享的,在某個方法中創建的對象,可以在方法調用結束后,依舊存在于堆中。當該對象不會再被引用時,卻仍然占用著堆中的空間,就造成了內存泄漏。 3、Java中的垃圾回收可以自動清空堆中不再使用的對象,防止內存泄漏,有效的使用空閑的內存。 ## 垃圾回收機制算法 垃圾回收算法需要做兩件事,一是發現無用信息對象,二是回收被無用對象占用的空間,使該空間可被程序再次使用。 ![](https://img.kancloud.cn/a7/41/a741b169e9171b43480311bd2562b4c2_2408x614.png) ### 引用計數算法 每個對象包含一個計數器,當有新的指向該對象的引用時,計數器加1,當引用移除時,計數器減1,當計數器為0時,認為該對象可以回收。 引用計數法有一個缺陷,無法檢測出循環引用。 ```java public class Main { public static void main(String[] args) { MyObject object1 = new MyObject(); MyObject object2 = new MyObject(); object1.object = object2; object2.object = object1; object1 = null; object2 = null; } } ``` 上面例子在最后將對象引用object1和object2都置為null后,他們所引用的對象均不會再被使用,但是兩個對象相互引用對方,導致兩者的計數器都不為0,因此不能被回收。 ### 可達性分析算法 ![](https://img.kancloud.cn/39/8f/398f2af8904fe969adf358ef7095b46c_345x262.png) 可達性分析算法中,每個對象都有用于標示該對象是否可達的標記信息。以棧和static數據為根,從根出發跟隨所有的引用,就可以找到所有的可到達對象。一個可到達對象,一定被根或者其他可到達對象引用。不可達對象就是需要垃圾回收的對象。 #### 標記清除算法(mark and sweep) 垃圾回收啟動時,Java程序暫停運行,JVM從根出發,找到所有的可到達對象并進行標記。然后,JVM掃描整個堆,找到剩余的不可到達對象,并清空這些對象占用的內存。 缺點是:1、標記和清除兩個過程效率都不高;2、標記清除后會產生大量內存碎片,以后給較大對象分配內存時,找不到足夠的連續內存空間。 #### 復制算法 復制算法下,將可用內存劃分為大小相等的兩塊,每次只使用其中一塊。當一塊使用完時,將還存活的對象復制到另一塊內存區域上,再把已使用過的那一塊一次清空。復制算法在對象存活率低時回收效率較高,缺點是內存空間的使用率只有一半。 目前商業虛擬機采用這種算法來回收新生代,但并沒有按1:1來劃分,而是按8:1:1來劃分的。也就是一個eden區,一個from區和一個to區,這樣只有10%的內存空間會被浪費。 #### 標記整理算法(copy and sweep) 使用復制算法當對象存活率較高時,效率就會變低。標記整理算法在找到所有可達對象并標記后, 將所有存活對象都向內存區域的一端移動,然后清理掉邊界以外的所有內存區域。 標記整理算法多用于回收老年代。 #### 分代回收算法(generational collection) ![](https://img.kancloud.cn/4d/5d/4d5d16f899a2b3cfa699580d2699e552_371x180.png) 堆分為三代:永久代(permanent)、老年代(tenured)、新生代(young)。新生代又分為三個區域,分別為:eden區、from區和to區(比例約為8:1:1)。 分代回收流程如下: 1、自從上次垃圾回收后創建的對象叫新生對象,存放于eden區,當eden區沒有空間再存放新生對象時,會觸發一次Minor GC,JVM會采用復制算法將eden區和from區的所有可到達對象復制到to區,to區緊密排列著復制來的對象,然后清空eden區和from區。經過此番操作后from區和to區互調位置,也就是原來的from區變成to區,to區變成from區。新生對象繼續存放在已經清空的eden區中。 2、當發現to區也已經放不下eden區和from區的所有對象時,會將部分對象放到老年代中。 3、即使to區沒有滿,JVM也會移動生命周期足夠久遠的對象到老年代。 4、如果老年代存儲已滿無法放入新的對象時,JVM會觸發Major GC,采用標記整理算法對老年代進行垃圾回收。 5、永久代中主要用于存放靜態文件,如Java類、方法等,永久代對于垃圾回收沒有顯著影響,一般回收廢棄常量和無用的類。 其中Minor GC發生頻率較高;而老年代對象由于存活時間較長,可到達標記率高,因此Major GC發生頻率較低。 # 字節碼與機器碼 ![](https://img.kancloud.cn/7f/ae/7faee11fc0780ec03c9b899f5d4acdcf_775x113.jpg) Java源代碼通過編譯變成字節碼(在Java程序中為.class文件,在Android程序中為.dex文件),然后字節碼按照模版中的規則解釋為機器碼(.oat文件),才可以被CPU解讀。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看