<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] <br> 接下來2節會一起來講解哪些垃圾需要回收、什么時候回收、常用的垃圾回收算法以及垃圾收集器 ![](https://box.kancloud.cn/29d85108388ba9a7b565b88ddaeb0e5f_605x591.jpg) 在java內存模型中,程序計數器、虛擬機棧、本地方法棧這些區域每個線程獨立擁有,與線程“同生共死”。每個棧幀內存大小是確定可知的,方法或線程結束時自動回收,這些區域不需要考慮內存回收問題。這里的垃圾回收指的是jvm堆內存和方法區的回收,這些區域內存在程序運行期間動態分配、動態回收,需要考慮選擇合適的垃圾回收算法。 ## 一、如何判斷對象是否已經“消亡“ ### 1.引用計數法 在Java中,引用和對象是有關聯的。如果要操作對象則必須用引用進行。因此,很顯然一個簡單的辦法是通過引用計數來判斷一個對象是否可以回收。簡單說,即一個對象如果沒有任何與之關聯的引用,即他們的引用計數都不為0,則說明對象不太可能再被用到,那么這個對象就是可回收對象。這種方法有個缺點就是無法檢測到引用環的存在。 ### 2.根搜索算法(GCRootsTracing)/可達性分析算法 為了解決引用計數法的循環引用問題,Java使用了可達性分析的方法。通過一系列的“GCroots”對象作為起點搜索。如果在“GCroots”和一個對象之間沒有可達路徑,則稱該對象是不可達的。 要注意的是,不可達對象不等價于可回收對象,不可達對象變為可回收對象至少要經過兩次標記過程。兩次標記后仍然是可回收對象,則將面臨回收。 ![](https://box.kancloud.cn/6a43a2ffb8e33ca670fc7581f4784ede_491x297.JPEG) 左圖中每個對象都存在引用鏈與GCRoots相連,表明對象還在,不能回收。 有圖中三個對象雖然互相引用,但是沒有鏈接與GCRoots相連,則可判斷它們是可回收的對象。 <br> 在Java語言中,可作為GC Roots的對象包括下面幾種: ??a) 虛擬機棧中引用的對象(棧幀中的本地變量表); ??b) 方法區中類靜態屬性引用的對象; ??c) 方法區中常量引用的對象; ??d) 本地方法棧中JNI(Native方法)引用的對象。 ## 二、常用垃圾回收算法 ### 1.標記-清除算法 ![](https://box.kancloud.cn/0028661ae688a6baac036e12bc1ff358_400x197.gif) 此算法分兩段執行,mark階段從引用根節點開始標記所有被引用的對象,尋找引用鏈,即仍然活著的對象。sweep階段直接將未標記的對象清除。該算法的缺點是需要停頓整個應用(stoptheworld),而且容易產生內存碎片。 標記清除算法:未標記的對象被清除 ### 2.標記-復制算法 此算法把內存劃分為相等大小的兩個區域,每一只使用其中一個,回收過程中將存活的對象全部復制到另一個區域中,清空原區域。在年輕代中eden區和兩個survivor區就是使用了此種算法。這種算法只復制存活的對象,成本較低,而且不會出現內存碎片問題,缺點是需要2倍的內存空間。 :-: ![](https://box.kancloud.cn/d4db06f3388f1411dd77a06b5ed7fe0d_413x143.gif) 標記--復制算法:只復制存活的對象 ### 3.標記-整理算法 該算法標記階段和Mark-Sweep一樣,但是在完成標記之后,它不是直接清理可回收對象,而是將存活對象都向一端移動,然后清理掉端邊界以外的內存。所以,特別適用于存活對象多,回收對象少的情況下。效率比“標記-清理”算法低,但不會產生內存碎片。 :-: ![](https://box.kancloud.cn/20a44fdd1b8d1c2cf7f0f19036f36446_407x138.gif) ### 3.4 **分代收集算法** ??**分代收集算法**是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根據對象存活的生命周期將內存劃分為若干個不同的區域。一般情況下將堆區劃分為老年代(Tenured Generation)和新生代(Young Generation),在堆區之外還有一個代就是永久代(Permanet Generation)。老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據不同代的特點采取最適合的收集算法。 :-: ![](https://box.kancloud.cn/36eaf1f739b5db5024fb6e343743b01f_563x308.jpg) #### 3.4.1 **年輕代(Young Generation)的回收算法(復制算法)** (回收主要以Copying為主) a) 所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。 <br> b) 新生代內存按照8:1:1的比例分為一個eden區和兩個survivor(survivor0,survivor1)區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在Eden區中生成。回收時先將eden區存活對象復制到一個survivor0區,然后清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活對象復制到另一個survivor1區,然后清空eden和這個survivor0區,此時survivor0區是空的,然后將survivor0區和survivor1區交換,即保持survivor1區為空, 如此往復。 <br> c) 當survivor1區不足以存放 eden和survivor0的存活對象時,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發一次Full GC(Major GC),也就是新生代、老年代都進行回收。 <br> d) 新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)。 <br> #### 3.4.2 **年老代(Old Generation)的回收算法(標記回收算法)**(回收主要以Mark-Compact為主) 1. JAVA?虛擬機提到過的處于方法區的永生代(Permanet?Generation),它用來存儲?class?類,常量,方法描述等。對永生代的回收主要包括廢棄常量和無用的類。 2. 對象的內存分配主要在新生代的?Eden?Space?和?Survivor?Space?的?From?Space(Survivor?目前存放對象的那一塊),少數情況會直接分配到老生代。 3. 當新生代的?Eden?Space?和?From?Space?空間不足時就會發生一次?GC?,進行?GC?后,?EdenSpace和FromSpace區的存活對象會被挪到ToSpace,然后將EdenSpace和FromSpace進行清理。 4. 如果ToSpace無法足夠存儲某個對象,則將這個對象存儲到老生代。 5. 在進行GC后,使用的便是EdenSpace和ToSpace了,如此反復循環。 6. 當對象在?Survivor?區躲過一次?GC?后,其年齡就會?+1?。默認情況下年齡到達?15?的對象會被移到老生代中。 簡單來說 a) 在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命周期較長的對象。 <br> b) 內存比新生代也大很多(大概比例是1:2),當老年代內存滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代對象存活時間比較長,存活率標記高。 <br> #### 3.4.3 **永久代(Permanent Generation)的回收算法** ??用于存放靜態文件,如Java類、方法等。永久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的永久代空間來存放這些運行過程中新增的類。永久代也稱方法區,永久代的垃圾回收主要包括類型的卸載和廢棄常量池的回收。當沒有對象引用一個常量的時候,該常量即可以被回收。而類型的卸載更加復雜。必須滿足一下三點,該類型的所有實例都被回收了,該類型的ClassLoader被回收了,該類型對應的java.lang.Class沒有在任何地方被引用,在任何地方都無法通過反射來實例化一個對象 。
                  <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>

                              哎呀哎呀视频在线观看