JVM構架、GC垃圾回收機制的理解

 JVM是Java Virtual Machine(Java虛擬機)的縮寫html

1.程序計數器算法

  它的做用能夠看作是當前線程所執行的字節碼的行號指示器。數據庫

每一個線程都有一個程序計算器,就是一個指針,指向方法區中的方法字節碼(下一個將要執行的指令代碼),由執行引擎讀取下一條指令,是一個很是小的內存空間,幾乎能夠忽略不記。網絡

二、棧區佈局

  棧也叫棧內存,主管Java程序的運行,是在線程建立時建立,它的生命期是跟隨線程的生命期,線程結束棧內存也就釋放,對於棧來講不存在垃圾回收問題,只要線程一結束該棧就Over,生命週期和線程一致,是線程私有的。spa

三、堆區線程

  堆這塊區域是JVM中最大的,應用的對象和數據都是存在這個區域,這塊區域也是線程共享的,也是 gc 主要的回收區,一個 JVM 實例只存在一個堆類存,堆內存的大小是能夠調節的。類加載器讀取了類文件後,須要把類、方法、常變量放到堆內存中,以方便執行器執行翻譯

 四、方法區指針

  用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。htm

 五、本地方法棧

  與虛擬機棧所發揮的做用是很是類似的,其區別不過是虛擬機棧爲虛擬機執行Java 方法(也就是字節碼)服務,而本地方法棧則是爲虛擬機使用到的Native 方法服務。

GC就是垃圾回收機制

  在系統運行過程當中,會產生一些無用的對象,這些對象佔據着必定的內存,若是不對這些對象清理回收無用對象的內存,可能會致使內存的耗盡,因此垃圾回收機制回收的是內存。同時GC回收的是堆區和方法區的內存。

 

JVM回收特色:(stop-the-world)當要進行垃圾回收時候,無論何種GC算法,除了垃圾回收的線程以外其餘任何線程都將中止運行。

被中斷的任務將會在垃圾回收完成後恢復進行。GC不一樣算法或是GC調優就是減小stop-the-world的時間。

垃圾收集算法

一、標記-清除(Mark-Sweep)算法

     這是最基礎的算法,標記-清除算法就如同它的名字樣,分爲「標記」和「清除」兩個階段:首先標記出全部須要回收的對象,標記完成後統一回收全部被標記的對象。這種算法的不足主要體如今效率和空間,從效率的角度講,標記和清除兩個過程的效率都不高;從空間的角度講,標記清除後會產生大量不連續的內存碎片, 內存碎片太多可能會致使之後程序運行過程當中在須要分配較大對象時,沒法找到足夠的連續內存而不得不提早觸發一次垃圾收集動做。標記-清除算法執行過程如圖:

二、複製(Copying)算法

      複製算法是爲了解決效率問題而出現的,它將可用的內存分爲兩塊,每次只用其中一塊,當這一塊內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已經使用過的內存空間一次性清理掉。這樣每次只須要對整個半區進行內存回收,內存分配時也不須要考慮內存碎片等複雜狀況,只須要移動指針,按照順序分配便可。複製算法的執行過程如圖:

     不過這種算法有個缺點,內存縮小爲了原來的一半,這樣代價過高了。如今的商用虛擬機都採用這種算法來回收新生代,不過研究代表1:1的比例很是不科學,所以新生代的內存被劃分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。每次回收時,將Eden和Survivor中還存活着的對象一次性複製到另一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor空間。HotSpot虛擬機默認Eden區和Survivor區的比例爲8:1,意思是每次新生代中可用內存空間爲整個新生代容量的90%。固然,咱們沒有辦法保證每次回收都只有很少於10%的對象存活,當Survivor空間不夠用時,須要依賴老年代進行分配擔保(Handle Promotion)。

三、標記-整理(Mark-Compact)算法

    複製算法在對象存活率較高的場景下要進行大量的複製操做,效率很低。萬一對象100%存活,那麼須要有額外的空間進行分配擔保。老年代都是不易被回收的對象,對象存活率高,所以通常不能直接選用複製算法。根據老年代的特色,有人提出了另一種標記-整理算法,過程與標記-清除算法同樣,不過不是直接對可回收對象進行清理,而是讓全部存活對象都向一端移動,而後直接清理掉邊界之外的內存。標記-整理算法的工做過程如圖:

四、分代收集算法

根據上面的內容,用一張圖歸納一下堆內存的佈局

     現代商用虛擬機基本都採用分代收集算法來進行垃圾回收。這種算法沒什麼特別的,無非是上面內容的結合罷了,根據對象的生命週期的不一樣將內存劃分爲幾塊,而後根據各塊的特色採用最適當的收集算法。大批對象死去、少許對象存活的(新生代),使用複製算法,複製成本低;對象存活率高、沒有額外空間進行分配擔保的(老年代),採用標記-清理算法或者標記-整理算法。

思考「GC是在何時,對什麼東西,作了什麼事情?」

  • 何時?

  從字面上翻譯過來就是何時觸發咱們的GC機制

  ①在程序空閒的時候。這個回答無力吐槽

  ②程序不可預知的時候/手動調用system.gc()。關於手動調用不推薦

  ③Java堆內存不足時,GC會被調用。當應用線程在運行,並在運行過程當中建立新對象,若這時內存空間不足,JVM就會強制地調用GC線程,以便回收內存用於新的分配。若GC一次以後仍不能知足內存分配的要求,JVM會再進行兩次GC做進一步的嘗試,若仍沒法知足要求,則 JVM將報「out of memory」的錯誤,Java應用將中止。就是

  這時候若是大家講出新生代和老年代的話或許會更細的瞭解一下Minor GC、Full GC、OOM何時觸發!

  建立對象是新生代的Eden空間調用Minor GC;當升到老年代的對象大於老年代剩餘空間Full GC;GC與非GC時間耗時超過了GCTimeRatio的限制引起OOM。

  • 什麼東西?

  從字面的意思翻譯過來就是能被GC回收的對象都有哪些特徵

  ①超出做用域的對象/引用計數爲空的對象。

  引用計數算法:給對象中添加一個引用計數器,每當有一個地方引用它時,計數器就加1;當引用失效時,計數器值就減1;任什麼時候刻計數器都爲0的對象就是不可能再被使用的。

  ②從GC Root開始搜索,且搜索不到的對象

  跟搜索算法:以一系列名爲 GC Root的對象做爲起點,從這些節點開始往下搜索,搜索走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈的時候,則就證實此對象是不可用的。

  這裏會提出一個思考,什麼樣的對象能成爲GC Root : 虛擬機中的引用的對象、方法區中的類靜態屬性引用的對象、方法區中常量引用的對象、本地方法棧中jni的引用對象。

  ③從root搜索不到,並且通過第一次標記、清理後,仍然沒有復活的對象。

  • 作什麼?

  不一樣年代、不一樣種類的收集器不少,不過整體的做用是刪除不使用的對象,騰出內存空間。補充一些諸如中止其餘線程執行、運行finalize等的說明。

ok  如今來回答一下咱們最上面的問題,上面時候容易發生內存泄露

  ①靜態集合類像HashMap、Vector等

  ②各類鏈接,數據庫鏈接,網絡鏈接,IO鏈接等沒有顯示調用close關閉,不被GC回收致使內存泄露。

  ③監聽器的使用,在釋放對象的同時沒有相應刪除監聽器的時候也可能致使內存泄露。

本文章轉自:https://www.cnblogs.com/dk2557/p/9585610.html

相關文章
相關標籤/搜索