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

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### [垃圾回收器如何工作](https://lingcoder.gitee.io/onjava8/#/book/06-Housekeeping?id=%e5%9e%83%e5%9c%be%e5%9b%9e%e6%94%b6%e5%99%a8%e5%a6%82%e4%bd%95%e5%b7%a5%e4%bd%9c) 如果你以前用過的語言,在堆上分配對象的代價十分高昂,你可能自然會覺得 Java 中所有對象(基本類型除外)在堆上分配的方式也十分高昂。然而,垃圾回收器能很明顯地提高對象的創建速度。這聽起來很奇怪——存儲空間的釋放影響了存儲空間的分配,但這確實是某些 Java 虛擬機的工作方式。這也意味著,Java 從堆空間分配的速度可以和其他語言在棧上分配空間的速度相媲美。 例如,你可以把 C++ 里的堆想象成一個院子,里面每個對象都負責管理自己的地盤。一段時間后,對象可能被銷毀,但地盤必須復用。在某些 Java 虛擬機中,堆的實現截然不同:它更像一個傳送帶,每分配一個新對象,它就向前移動一格。這意味著對象存儲空間的分配速度特別快。Java 的"堆指針"只是簡單地移動到尚未分配的區域,所以它的效率與 C++ 在棧上分配空間的效率相當。當然實際過程中,在簿記工作方面還有少量額外開銷,但是這部分開銷比不上查找可用空間開銷大。 你可能意識到了,Java 中的堆并非完全像傳送帶那樣工作。要是那樣的話,勢必會導致頻繁的內存頁面調度——將其移進移出硬盤,因此會顯得需要擁有比實際需要更多的內存。頁面調度會顯著影響性能。最終,在創建了足夠多的對象后,內存資源被耗盡。其中的秘密在于垃圾回收器的介入。當它工作時,一邊回收內存,一邊使堆中的對象緊湊排列,這樣"堆指針"就可以很容易地移動到更靠近傳送帶的開始處,也就盡量避免了頁面錯誤。垃圾回收器通過重新排列對象,實現了一種高速的、有無限空間可分配的堆模型。 要想理解 Java 中的垃圾回收,先了解其他系統中的垃圾回收機制將會很有幫助。一種簡單但速度很慢的垃圾回收機制叫做*引用計數*。每個對象中含有一個引用計數器,每當有引用指向該對象時,引用計數加 1。當引用離開作用域或被置為**null**時,引用計數減 1。因此,管理引用計數是一個開銷不大但是在程序的整個生命周期頻繁發生的負擔。垃圾回收器會遍歷含有全部對象的列表,當發現某個對象的引用計數為 0 時,就釋放其占用的空間(但是,引用計數模式經常會在計數為 0 時立即釋放對象)。這個機制存在一個缺點:如果對象之間存在循環引用,那么它們的引用計數都不為 0,就會出現應該被回收但無法被回收的情況。對垃圾回收器而言,定位這樣的循環引用所需的工作量極大。引用計數常用來說明垃圾回收的工作方式,但似乎從未被應用于任何一種 Java 虛擬機實現中。 在更快的策略中,垃圾回收器并非基于引用計數。它們依據的是:對于任意"活"的對象,一定能最終追溯到其存活在棧或靜態存儲區中的引用。這個引用鏈條可能會穿過數個對象層次,由此,如果從棧或靜態存儲區出發,遍歷所有的引用,你將會發現所有"活"的對象。對于發現的每個引用,必須追蹤它所引用的對象,然后是該對象包含的所有引用,如此反復進行,直到訪問完"根源于棧或靜態存儲區的引用"所形成的整個網絡。你所訪問過的對象一定是"活"的。注意,這解決了對象間循環引用的問題,這些對象不會被發現,因此也就被自動回收了。 在這種方式下,Java 虛擬機采用了一種*自適應*的垃圾回收技術。至于如何處理找到的存活對象,取決于不同的 Java 虛擬機實現。其中有一種做法叫做停止-復制(stop-and-copy)。顧名思義,這需要先暫停程序的運行(不屬于后臺回收模式),然后將所有存活的對象從當前堆復制到另一個堆,沒有復制的就是需要被垃圾回收的。另外,當對象被復制到新堆時,它們是一個挨著一個緊湊排列,然后就可以按照前面描述的那樣簡單、直接地分配新空間了。 當對象從一處復制到另一處,所有指向它的引用都必須修正。位于棧或靜態存儲區的引用可以直接被修正,但可能還有其他指向這些對象的引用,它們在遍歷的過程中才能被找到(可以想象成一個表格,將舊地址映射到新地址)。 這種所謂的"復制回收器"效率低下主要因為兩個原因。其一:得有兩個堆,然后在這兩個分離的堆之間來回折騰,得維護比實際需要多一倍的空間。某些 Java 虛擬機對此問題的處理方式是,按需從堆中分配幾塊較大的內存,復制動作發生在這些大塊內存之間。 其二在于復制本身。一旦程序進入穩定狀態之后,可能只會產生少量垃圾,甚至沒有垃圾。盡管如此,復制回收器仍然會將所有內存從一處復制到另一處,這很浪費。為了避免這種狀況,一些 Java 虛擬機會進行檢查:要是沒有新垃圾產生,就會轉換到另一種模式(即"自適應")。這種模式稱為標記-清掃(mark-and-sweep),Sun 公司早期版本的 Java 虛擬機一直使用這種技術。對一般用途而言,"標記-清掃"方式速度相當慢,但是當你知道程序只會產生少量垃圾甚至不產生垃圾時,它的速度就很快了。 "標記-清掃"所依據的思路仍然是從棧和靜態存儲區出發,遍歷所有的引用,找出所有存活的對象。但是,每當找到一個存活對象,就給對象設一個標記,并不回收它。只有當標記過程完成后,清理動作才開始。在清理過程中,沒有標記的對象將被釋放,不會發生任何復制動作。"標記-清掃"后剩下的堆空間是不連續的,垃圾回收器要是希望得到連續空間的話,就需要重新整理剩下的對象。 "停止-復制"指的是這種垃圾回收動作不是在后臺進行的;相反,垃圾回收動作發生的同時,程序將會暫停。在 Oracle 公司的文檔中會發現,許多參考文獻將垃圾回收視為低優先級的后臺進程,但是早期版本的 Java 虛擬機并不是這么實現垃圾回收器的。當可用內存較低時,垃圾回收器會暫停程序。同樣,"標記-清掃"工作也必須在程序暫停的情況下才能進行。 如前文所述,這里討論的 Java 虛擬機中,內存分配以較大的"塊"為單位。如果對象較大,它會占用單獨的塊。嚴格來說,"停止-復制"要求在釋放舊對象之前,必須先將所有存活對象從舊堆復制到新堆,這導致了大量的內存復制行為。有了塊,垃圾回收器就可以把對象復制到廢棄的塊。每個塊都有年代數來記錄自己是否存活。通常,如果塊在某處被引用,其年代數加 1,垃圾回收器會對上次回收動作之后新分配的塊進行整理。這對處理大量短命的臨時對象很有幫助。垃圾回收器會定期進行完整的清理動作——大型對象仍然不會復制(只是年代數會增加),含有小型對象的那些塊則被復制并整理。Java 虛擬機會監視,如果所有對象都很穩定,垃圾回收的效率降低的話,就切換到"標記-清掃"方式。同樣,Java 虛擬機會跟蹤"標記-清掃"的效果,如果堆空間出現很多碎片,就會切換回"停止-復制"方式。這就是"自適應"的由來,你可以給它個啰嗦的稱呼:"自適應的、分代的、停止-復制、標記-清掃"式的垃圾回收器。 Java 虛擬機中有許多附加技術用來提升速度。尤其是與加載器操作有關的,被稱為"即時"(Just-In-Time, JIT)編譯器的技術。這種技術可以把程序全部或部分翻譯成本地機器碼,所以不需要 JVM 來進行翻譯,因此運行得更快。當需要裝載某個類(通常是創建該類的第一個對象)時,編譯器會先找到其**.class**文件,然后將該類的字節碼裝入內存。你可以讓即時編譯器編譯所有代碼,但這種做法有兩個缺點:一是這種加載動作貫穿整個程序生命周期內,累加起來需要花更多時間;二是會增加可執行代碼的長度(字節碼要比即時編譯器展開后的本地機器碼小很多),這會導致頁面調度,從而一定降低程序速度。另一種做法稱為*惰性評估*,意味著即時編譯器只有在必要的時候才編譯代碼。這樣,從未被執行的代碼也許就壓根不會被 JIT 編譯。新版 JDK 中的 Java HotSpot 技術就采用了類似的做法,代碼每被執行一次就優化一些,所以執行的次數越多,它的速度就越快。
                  <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>

                              哎呀哎呀视频在线观看