天天看點

Java記憶體管理之垃圾回收機制

Java 目錄:https://blog.csdn.net/dkbnull/article/details/87932486

        Java的垃圾回收機制可以監控每個Java對象,當某個對象處于不可達狀态時,就回收該對象所占用的記憶體;同時,垃圾回收機制還對記憶體進行監控,負責清理記憶體配置設定、回收中産生的記憶體碎片。

        對于Java程式來說,垃圾回收機制完成的這兩項工作工作量都很大,是以垃圾回收機制成為限制Java程式運作效率的重要因素。是以高效的垃圾回收機制就顯得至關重要。高效的垃圾回收機制既能夠保證垃圾回收的快速運作,又不能導緻Java程式出現卡頓。

        前面說垃圾回收機制監控每個Java對象,但他不可能實時監控每個Java對象的狀态(這将非常耗性能),是以當一個對象失去引用後,他并不是被立即回收,而是等到垃圾回收機制運作的時候才進行回收。

        對于一個垃圾回收器的設計算法來說,主要有串行回收、并行回收;并發執行、應用程式停止執行;壓縮、不壓縮、複制的設計。

        串行回收:不管系統有多少個CPU,始終隻用一個CPU來執行垃圾回收操作。

        并行回收:多個CPU并行執行垃圾回收操作。

        比較:并行回收執行效率高,但複雜度增加,會導緻記憶體碎片增加等問題。

        并發執行:垃圾回收與應用程式同時運作。

        應用程式終止:在執行垃圾回收時應用程式會暫停。

        比較:并發執行的垃圾回收系統開銷大,需要更多的堆記憶體,和應用程式之間存在執行沖突問題(比如應用程式在垃圾回收的時候修改對象)。

        壓縮:把所有處于可達狀态的對象移動到一起,然後将剩餘的記憶體全部清理。

        不壓縮:隻回收記憶體。

        複制:将所有處于可達狀态的對象複制到另一塊相同的記憶體中,對原記憶體進行全部清理。

        比較:壓縮式垃圾回收可以減少記憶體碎片;不壓縮式會有較多記憶體碎片,與壓縮式相比回收記憶體快,但配置設定記憶體慢;複制式不會産生記憶體碎片,但複制時消耗時間并且需要額外的記憶體。

        現行的垃圾回收機制采用分代的方式來進行垃圾回收,針對不同的分代采用不同的回收設計。

        根據對象生存時間的長短,把堆記憶體分為3個代:Young代,Old代,Permanent代。

        垃圾回收機制根據不同的分代的特點采用不同的回收算法。

        Young代

        采用複制式垃圾回收。

        Young代中處于可達狀态的對象數量比較少,可複制成本不大,可以發揮複制算法的優勢。

        Young代由一個Eden區和兩個Survivor區構成,大部分對象建立時先配置設定到Eden區中,一些大的對象可以直接進入Old區,Survivor區的對象為在Young代中經曆過至少一次垃圾回收,這些對象在進入Old代之前先保留在Survivor區。同一時間,兩個Survivor區一個用來儲存對象,另一個為空,用來在垃圾回收時儲存Young代中的對象。

        垃圾回收時,Eden區和第一個Survivor區的可達狀态的對象都複制到第二個Survivor區,然後清空Eden區和第一個Survivor區。此時第一個Survivor區變成空閑區,下一次垃圾回收時将Eden區和第二個Survivor區的可達狀态的對象複制到該區。

        Old代

        如果Young代中的對象經過多次垃圾回收後依然沒有被回收掉,這個對象會被移動到Old代。

        Old代中的對象大部分都是從Young代中轉移過來的,經過了多次垃圾回收,是以這些對象不會輕易變成不可達狀态。是以Old代執行垃圾回收的頻率相對較低。

        随着Young代中的對象不斷轉移到Old代,Old代中存儲了較多的對象,是以Old代的存儲空間一般比Young代大,而且Old代每次執行垃圾回收的時間也比較長。

        綜上考慮,Old代使用壓縮式垃圾回收,這樣可以避免Old代大量複制對象,同時由于Old代一般不會有對象程式設計不可達狀态,是以回收過程中不會産生大量碎片。

        Permanent代

        Permanent代主要用于裝載Class、方法等資訊,垃圾回收機制通常不會回收Permanent代中的對象。