成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

來說說垃圾回收怎么樣~

云計算 虛擬化
JVM 的自動內存管理,讓原本應該是開發人員去做的事情,變成了垃圾回收器來做的事情,既然是別人幫忙做的事情,那么可能就不是自己想要的,所以就需要我們了解一下垃圾回收相關的內容。

[[354376]]

本文轉載自微信公眾號「Java極客技術」,作者鴨血粉絲 。轉載本文請聯系Java極客技術公眾號。  

JVM 的自動內存管理,讓原本應該是開發人員去做的事情,變成了垃圾回收器來做的事情

既然是別人幫忙做的事情,那么可能就不是自己想要的,所以就需要我們了解一下垃圾回收相關的內容

引用計數法與可達性分析

垃圾回收,垃圾回收,那就是有的內存分配給了一些對象,但是這些對象已經用完了,那么它所占用的內存也就應該該釋放掉了,卻還沒有釋放

那么,這里就有個問題:該如何確定一個對象用完了呢?

其中一種方法就是引用計數法

引用計數法就是給每個對象添加一個引用計數器,來統計指向該對象的引用個數

比如:如果有一個引用,被賦值為某一個對象,那么這個對象的引用計數器就 +1 ,如果一個指向這個對象的引用,被賦值為了其他的值,那么這個對象的引用計數器就 -1 ,這樣如果這個對象的引用計數器為 0 ,我們就可以認為這個對象已經使用完畢,它所占用的內存空間可以回收掉了

這種方案聽上去無懈可擊,但是有一個致命的漏洞,就是沒辦法處理循環引用的問題

比如說: A 和 B 互相引用,除此之外也沒有其他的引用指向 A 或者 B ,在這種情況下,其實 A 和 B 所占用的內存就可以釋放掉了,但是因為它們互相都有引用,所以此時的引用計數器并不為 0 ,在這種情況下,就不能對它們進行回收

現在只是兩個對象,如果再來兩個,再來兩個,這樣循環引用的對象多了之后,就會造成內存泄露

基于引用計數法的弊端,當前 JVM 主流的垃圾回收器采取的是可達性分析算法

這個算法本質就是將一系列的 GC Roots 作為初始的存活對象合集( live set ),然后從這個合集出發,探索所有能夠被該集合引用到的對象,并把這些對象加入到集合中來,這個過程就叫做標記( mark ),遍歷到最后,沒有被探索到的對象就是可以回收的對象

那么什么是 GC Roots 嘞?一般包括(但不限于)以下幾種:

  • Java 方法棧楨中的局部變量
  • 已加載類的靜態變量
  • JNI handles
  • 已啟動并且沒有停止的 Java 線程

剛才說因為引用計數法存在循環引用的問題,所以目前主流垃圾回收器選用的都是可達性分析法,也就是說,它解決了循環引用問題,其實這一點也比較好理解,雖然 A 和 B 相互引用,但是這個時候從 GC Roots 開始出發,是沒有辦法到達 A 和 B 的,那么就不會把它們放到存活對象合集之中,自然也就會被回收掉

但是在實際中還是會有問題的,比如:在多線程環境下,就會有其他線程更新已經訪問過的對象中的引用,但是是多線程并行的嘛,這個時候可達性分析法已經把這個引用設置成了 null ,或者這個對象還在使用,但可達性分析法把它標記為了沒有被訪問過的對象,被回收掉了,這種情況可能直接導致 JVM 崩潰掉

Stop-the-world & safepoint

既然可達性分析法也有自己的一些缺陷,總得有解決方案吧?比較暴力的一種方法就是 Stop-the-world ,估計聽名字也能知道,就是讓全世界都停下來,也就是說,在進行垃圾回收的時候,其他所有非垃圾回收線程的工作都需要停下來,先讓垃圾回收器工作完畢再說。這就是所謂的暫停時間( GC pause )

Stop-the-world 是通過安全點( safepoint )機制來實現的。啥意思嘞?咱先想個場景,現在你敲代碼敲的特別開心,又有思路,狀態又好,美滋滋的正在工作,突然毫無緣由的就讓你現在不準敲代碼,你會不會不開心?好不容易思路來了對吧,就一點兒理由都不給的就讓我停下,不合理吧?

同樣的場景,一個線程現在跑的特別 happy ,而且再有一秒鐘就完成了任務,這個時候 JVM 收到了 Stop-the-world 請求,二話不說就把所有的線程給停掉,不太好吧?那么這個時候安全點( safepoint )機制就登場了。有了安全點機制,當 JVM 收到 Stop-the-world 請求的時候,它就會等待所有的線程都達到安全點,才允許請求 Stop-the-world 的線程進行獨占的工作

那么,什么時候是安全點呢?舉個例子來說:當 Java 程序通過 JNI 執行本地代碼時,如果這段代碼不訪問 Java 對象,不調用 Java 方法,不返回到原 Java 方法,那么 Java 虛擬機的堆棧就不會發生改變,那這段本地代碼就可以作為一個安全點。只要不離開這個安全點, JVM 就可以在垃圾回收的同時,繼續運行這段本地代碼

因為本地代碼需要通過 JNI 的 API 來完成上述三個操作,因此 JVM 只需要在 API 的入口處進行安全點檢測( safepoint poll ),看看有沒有其他線程請求停留在安全點這里,就可以在必要的時候掛起當前線程

垃圾回收的三種方式

當標記好存活的對象之后,就可以進行垃圾回收了

主流的垃圾回收方式,可以分為三種:清除( sweep ),壓縮( compact ),復制( copy )

清除,就是把死亡對象所占據的內存標記成空閑內存,并把它記錄在一個空閑列表( free list )中,當需要新建對象的時候,就直接在空閑列表中尋找空閑內存,劃分給新建的對象就完了

但是這里會產生一個問題,因為死亡的對象所占據的內存可能是隨機的,回收完畢之后,內存就是碎片化的,如果此時有對象申請一塊連續的內存空間,盡管碎片化的內存空間是夠用的,也沒辦法進行分配

壓縮,就是把存活的對象聚集到內存區域的起始位置,這樣就可以留下一段連續的內存空間。這樣去做的話,可以解決內存碎片化的問題,代價就是壓縮算法帶來的性能開銷

復制,就是把內存區域分成兩等分,分別用兩個指針 from 和 to 來維護,并且只是用 from 指針指向的內存區域來分配內存。當進行垃圾回收時,就把存活的對象復制到 to 指針指向的內存區域中,并且交換 from 指針和 to 指針的內容。

復制這種方式也可以解決內存碎片化的問題,但是它的缺點也是比較明顯的,因為把內存區域分成了兩等分嘛,那利用率就比較低咯,最高也是 50% 了,不能再高了

垃圾回收在 JVM 中的應用

上面說的三種垃圾回收方式是理論上的,那么在 JVM 中是如何應用的呢?

這就先要來了解下 JVM 的堆劃分,大概就是這樣子:

JVM 將堆劃分為新生代和老年代,在新生代中又劃分為 Eden 區,還有兩個大小相同的 Survivor 區

當程序調用 new 指令時,會在 Eden 區中劃出一塊作為存儲對象的內存,但是因為堆空間是線程共享的,所以在這里面劃分空間的話就需要同步,要不然出現了兩個對象共用一段內存,那不就該打架了嘛

JVM 為了避免兩個對象打架的事情發生,就讓每個線程向 JVM 申請一段連續的內存,來作為線程私有的 TLAB ( Thread Local Allocation Buffer ,對應虛擬機參數 -XX:+UseTLAB ,默認開啟的)

Eden 區一直進行分配,總有空間分配完畢的時候,該怎么辦?此時 JVM 就會觸發一次 Minor GC ,來收集新生代的垃圾,存活下來的對象就會被送到 Survivor 區

在圖中可以看到, Survivor 區有兩個,一個是 from ,一個是 to ,其中 to 指向的 Survivor 區是空的

當發生 Minor GC 時, Eden 區和 from 指向的 Survivor 區中的存活對象會被復制到 to 指向的 Survivor 區,然后交換 from 和 to 指針,這樣就保證了下一次 Minor GC 時, to 指向的 Survivor 區還是空的

同時 JVM 會記錄 Survivor 區的對象一共被來回復制了幾次,如果一個對象被復制的次數為 15 (對應虛擬機參數 -XX:+MaxTenuringThreshold ),這個對象就會被晉升( promote )到老年代

那么在發生 Minor GC 時,采用哪種垃圾回收方式會比較好一些呢?采用復制方式,也就是 標記-復制 算法會好一些。為什么呢?因為在新生代中,大部分的 Java 對象只存活一小段時間,那么我們就可以采用耗時比較短的垃圾回收算法,讓大部分的垃圾都能在新生代被回收掉。使用 標記-復制 算法的話,理想情況下就是 Eden 區中的對象基本都死亡了,那么需要復制的數據非常少,此時這種算法的優勢就被極大的體現了出來

 

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2021-01-09 14:03:37

Vrrp協議網關

2017-08-04 10:53:30

回收算法JVM垃圾回收器

2022-01-20 10:34:49

JVM垃圾回收算法

2021-01-04 10:08:07

垃圾回收Java虛擬機

2022-03-21 11:33:11

JVM垃圾回收器垃圾回收算法

2014-02-18 11:24:07

云計算PaaS

2020-12-14 11:35:22

SPI Java機制

2021-11-05 15:23:20

JVM回收算法

2018-04-24 14:34:54

機器學習機器人互聯網

2010-12-13 11:14:04

Java垃圾回收算法

2023-08-08 10:29:55

JVM優化垃圾回收

2020-07-09 08:26:42

Kubernetes容器開發

2009-06-25 17:48:24

Java垃圾回收

2021-03-03 08:13:57

模式垃圾回收

2023-12-19 21:52:51

Go垃圾回收開發

2019-07-19 15:42:57

Hadoop大數據YuniKorn

2023-06-30 08:23:36

Spring!SolonJavalin

2015-07-23 11:49:31

程序猿

2024-08-20 16:27:54

2009-12-30 10:14:29

JVM垃圾回收
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产视频一二三区 | 成人免费影院 | 污片在线免费观看 | 亚洲三区在线观看 | 国产色在线 | 久久久久亚洲 | 超碰导航 | 午夜理伦三级理论三级在线观看 | 一本色道精品久久一区二区三区 | 久久久久成人精品 | 自拍偷拍在线视频 | 亚洲欧美少妇 | 亚洲精品一区在线 | 亚洲精品久久久久中文字幕欢迎你 | 中文字幕精品一区 | av中文字幕在线 | 亚洲精品乱码 | 最新中文字幕在线播放 | 视频一区在线观看 | 国产精品久久av | 国产精品久久国产精品久久 | 国产一区久久精品 | 一级毛片在线看 | 欧美精品中文字幕久久二区 | 午夜av影院| 91精品国产综合久久久久久丝袜 | 国产福利在线看 | 国产精品a免费一区久久电影 | 久久美女网| 亚洲免费一区 | 亚洲精品久久久一区二区三区 | 国产一区二区三区视频免费观看 | 亚洲国产精品区 | 西西裸体做爰视频 | 国产乱精品一区二区三区 | 久久av影院 | 久久毛片网站 | 亚洲福利av| 精品国产99 | 欧美日韩在线免费观看 | 一区二区国产精品 |