[TOC]
<br/>
> ### 判斷對象是否已死亡
* **引用計數法**,引用計數法無法解決循環引用的問題。
* **根搜索算法**,通過一系列的稱為 `GC Roots`的對象作為起點,從這些節點開始向下搜索,節點所走過的路徑稱為引用鏈,當一個對象到 GC Roots 沒有任何引用鏈相連的話,則證明此對象是不可用的。如下可作為`Root`:
* java虛擬機棧中引用的對象
* 本地方法棧中引用的對象
* 方法區的靜態屬性引用的對象
* 方法區的常量引用的對象
<br/>
> ### 四種引用類型
* **強引用**
* **軟引用**,當系統內存不夠時才回收軟引用的對象。舉例,博客的列表緩存。
* 通過軟引用對博客文章進行緩存
* **弱引用**,當垃圾回收器發現某塊內存上只有弱引用(沒有強引用)時,不管當前內存是否足夠都會回收這塊內存。
* 優惠券`coupanList`和用戶`userList`的對應關系,通過`WeakHashMap<Coupan, <List<>WeakReference<User>>>`類型的`weakCoupanHM`來存儲其對應關系。
* **虛引用**
<br/>
> ### 垃圾收集算法
* **標記-清除算法**,會產生大量不連續的內存碎片。一般是老年代收集算法`cms`
* **復制算法**,將內存按大小分為兩塊,當其中一塊用完將存活對象復制到另一塊,并將前一塊進行回收。一般是新生代收集算法,新生代對象回收頻繁且大部分對象都會被回收。`Eden`區和兩塊`Survivor`區,大小比為`8 : 1 : 1`,當復制算法收集時`Survivor`區大小不夠時,需要依賴老年代進行分配擔保。
* **標記-整理算法**,在標記清除的基礎上對所有存活對象向內存一側移動,再進行回收,避免了內存碎片的問題。
<br/>
> ### 安全點
* 安全點意味著在這個點時,所有工作線程的狀態是確定的,JVM 就可以安全地執行 GC 。
* 一般會在如下幾個位置選擇安全點:循環的末尾,方法臨返回前,調用方法之后,拋異常的位置。
* **主動式中斷**:在 GC 發生時,不直接操作線程中斷,而是簡單地設置一個標志,讓各個線程執行時主動輪詢這個標志(標志位置與安全點重合),發現中斷標志為真時就自己中斷掛起,JVM采用主動式中斷。**搶斷式中斷**:在 GC 發生時,首先中斷所有線程,如果發現線程未執行到 Safe Point,就恢復線程讓其運行到 Safe Point 上。
<br/>
> ### 并發`concurrent` 和 并行`paralla`

* **并發**`concurrent` 是兩個隊列交替使用一臺咖啡機
* **并行**`paralla` 并行是兩個隊列同時使用兩臺咖啡機
* 并發`concurrent` 和 并行`paralla`都可以是多個線程,就看這些線程能不能同時間被(多個)CPU執行,如果可以就說明是并行,而并發是指多個線程被(一個)CPU輪流切換執行。
<br/>
> ### 垃圾收集器

* **新生代收集器**: `Serial` 、`ParNew`、 `Parallel Scavenge`
* **老年代收集器**: `Serial Old` 、`Parallel Old`、 `CMS`
* 堆內存垃圾收集器:`G1`
* `JVM`默認收集器,新生代`Parallel Scavende`,老年代`Serial Old`

> ### `Serial` 收集器
* `Serial` 是一款用于新生代的單線程收集器,采用復制算法進行垃圾收集。`Serial `進行垃圾收集時,只用一條線程執行垃圾收集工作,它在收集的同時,所有的用戶線程必須暫停(`Stop The World`)。
* **優點**:簡單而高效(與其他收集器的單線程比),對于限定單個`CPU`的環境來說,Serial收集器減少了線程交互的開銷。 所以運行在`Client`模式下的虛擬機來說是一個不錯的選擇

> ### `ParNew` 收集器
* `ParNew` 就是一個 `Serial` 的多線程版本,針對新生代,其它與Serial并無區別。`ParNew` 在單核 CPU 環境并不會比 `Serial` 收集器達到更好的效果,它默認開啟的收集線程數和 `CPU` 數量一致,可以通過 `-XX:ParallelGCThreads` 來設置垃圾收集的線程數。
* **適用場景**:多核服務器;與 `CMS` 收集器搭配使用。當使用` -XX:+UserConcMarkSweepGC `來選擇 CMS 作為老年代收集器時,新生代收集器默認就是 `ParNew`,也可以用 `-XX:+UseParNewGC `來指定使用 ParNew 作為新生代收集器。

> ### `Parallel Scavenge` 收集器
* `Parallel Scavenge` 也是一款用于新生代的多線程收集器,與 `ParNew` 的不同之處是`ParNew `的目標是盡可能縮短垃圾收集時用戶線程的停頓時間,`Parallel Scavenge `的目標是達到一個可控制的吞吐量。吞吐量就是 CPU 執行用戶線程的的時間與 CPU 執行總時間的比值。
* **適用場景**:注重吞吐量,高效利用 CPU,需要高效運算且不需要太多交互。可以通過` -XX:MaxGCPauseMillis` 來設置收集器盡可能在多長時間內完成內存回收,可以通過` -XX:GCTimeRatio` 來精確控制吞吐量。

> ### `Serial Old` 收集器
* `Serial Old` 收集器是 `Serial` 的老年代版本,同樣是一個單線程收集器,采用標記-整理算法。
* **適用場景**:Client 模式(桌面應用);單核服務器;與 Parallel Scavenge 收集器搭配;作為 CMS 收集器的后備預案。

> ### `Parallel Old` 收集器
* `Parallel Old` 收集器是 `Parallel Scavenge `的老年代版本,是一個多線程收集器,采用標記-整理算法。可以與 `Parallel Scavenge` 收集器搭配,可以充分利用多核 CPU 的計算能力。
* **適用場景**:與`Parallel Scavenge` 收集器搭配使用;注重吞吐量。jdk7、jdk8 默認使用該收集器作為老年代收集器,使用` -XX:+UseParallelOldGC `來指定使用 `Paralle Old `收集器。

> ### `CMS`收集器
* `CMS` 收集器是一種以最短回收停頓時間為目標的收集器,以 “ 最短用戶線程停頓時間 ” 著稱。優點:并發收集、低停頓,缺點:標記-清除算法導致的空間碎片,無法處理浮動垃圾(并發清除時,用戶程序仍在運行所產生的垃圾)
* 整個垃圾收集過程分為 4 個步驟:
* ① 初始標記:標記一下 GC Roots 能直接關聯到的對象,速度較快。`stop the world`
* ② 并發標記:進行 GC Roots Tracing,標記出全部的垃圾對象,耗時較長。
* ③ 重新標記:修正并發標記階段引用戶程序繼續運行而導致變化的對象的標記記錄,耗時較短。`stop the world`
* ④ 并發清除:用標記-清除算法清除垃圾對象,耗時較長。
* 整個過程耗時最長的并發標記和并發清除都是和用戶線程一起工作,所以從總體上來說,CMS 收集器垃圾收集可以看做是和用戶線程并發執行的。

> ### `G1`收集器
* `G1` 收集器是 jdk1.7 才正式引用的商用收集器,現在已經成為 jdk9 默認的收集器。前面幾款收集器收集的范圍都是新生代或者老年代,`G1` 進行垃圾收集的范圍是整個堆內存,它采用 “ 化整為零 ” 的思路,把整個堆內存劃分為多個大小相等的獨立區域(`Region`),在 G1 收集器中還保留著新生代和老年代的概念,它們分別都是一部分 `Region`,如下圖:
](https://i.loli.net/2019/03/12/5c8747986ce56.png)
* `G1` 收集器可以 “ **建立可預測的停頓時間模型** ”,`G1` 采用**增量回收**的方式,每次回收一些區塊,而不是整堆回收。它維護了一個列表用于記錄每個` Region` 回收的價值大小(回收后獲得的空間大小以及回收所需時間的經驗值),這樣可以保證` G1 `收集器在有限的時間內可以獲得最大的回收效率。

* G1 收集器收集器收集過程有初始標記、并發標記、最終標記、篩選回收,和 CMS 收集器前幾步的收集過程很相似:
① 初始標記:標記出 `GC Roots` 直接關聯的對象,這個階段速度較快,需要停止用戶線程,單線程執行。
② 并發標記:從 `GC Root `開始對堆中的對象進行可達新分析,找出存活對象,這個階段耗時較長,但可以和用戶線程并發執行。
③ 最終標記:修正在并發標記階段引用戶程序執行而產生變動的標記記錄。
④ 篩選回收:篩選回收階段會對各個` Region` 的回收價值和成本進行排序,根據用戶所期望的 GC 停頓時間來指定回收計劃(用最少的時間來回收包含垃圾最多的區域,這就是 `Garbage First `的由來——第一時間清理垃圾最多的區塊),這里為了提高回收效率,并沒有采用和用戶線程并發執行的方式,而是停頓用戶線程。
* **適用場景**:要求盡可能可控 `GC `停頓時間;內存占用較大的應用。可以用`-XX:+UseG1GC`使用` G1 `收集器,jdk9 默認使用` G1` 收集器。
<br/>
> ### `JVM`分代收集
* 對象優先在`Eden`分配。當`Eden`區沒有足夠的空間進行分配時,虛擬機就會發動一次新生代的垃圾回收動作(`Minor GC`)。
* 大對象直接進入老年代,大對象指大量連續內存空間的Java對象,比如那種很長的字符串以及數組。`JVM`中提供了`-XX:PretenureSizeThreshold`,令大于這個設置值的對象直接在老年代分配,這樣做的目的是避免`Eden`區及兩個`Survivor`區之前發生大量的內存復制。
* 虛擬機會給每一個對象定義了一個對象年齡(`Age`)計數器。如果對象在Eden出生并經過第一次`Minor GC`后仍然存活,并且能被`Survivor`容納的話,將其移動到`Survivor`空間中,并且對象年齡設為1,每經歷一次`Minor GC`年齡加1,默認達到15歲進入老年代,可以通過參數`-XX:MaxTenuringThreshold`設置年齡閾值。(如果在`Survivor`空間中相同年齡所有對象大小的總和大于`Survivor`空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代,無序等到`MaxTeuringThreshold`所要求的年齡。)
<br/>
<br/>
***
參考:
[7種JVM垃圾收集器特點,優劣勢、及使用場景](https://www.zhihu.com/search?type=content&q=%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8)
[并發與并行的區別](https://www.zhihu.com/question/33515481/answer/199929767)
[G1 垃圾收集器介紹](https://www.javadoop.com/post/g1)
[Java虛擬機系列之垃圾回收機制(1)](https://juejin.im/post/5b2fbea76fb9a00e5d798af3)
[Java虛擬機系列之垃圾回收機制(2)](https://juejin.im/post/5b30ea636fb9a00e3b7fb1f9)
- asD
- Java
- Java基礎
- Java編譯器
- 反射
- collection
- IO
- JDK
- HashMap
- ConcurrentHashMap
- LinkedHashMap
- TreeMap
- 阻塞隊列
- java語法
- String.format()
- JVM
- JVM內存、對象、類
- JVM GC
- JVM監控
- 多線程
- 基礎概念
- volatile
- synchronized
- wait_notify
- join
- lock
- ThreadLocal
- AQS
- 線程池
- Spring
- IOC
- 特性介紹
- getBean()
- creatBean()
- createBeanInstance()
- populateBean()
- AOP
- 基本概念
- Spring處理請求的過程
- 注解
- 微服務
- 服務注冊與發現
- etcd
- zk
- 大數據
- Java_spark
- 基礎知識
- Thrift
- hdfs
- 計算機網絡
- OSI七層模型
- HTTP
- SSL
- 數據庫
- Redis
- mysql
- mybatis
- sql
- 容器
- docker
- k8s
- nginx
- tomcat
- 數據結構/算法
- 排序算法
- 快排
- 插入排序
- 歸并排序
- 堆排序
- 計算時間復雜度
- leetcode
- LRU緩存
- B/B+ 樹
- 跳躍表
- 設計模式
- 單例模式
- 裝飾者模式
- 工廠模式
- 運維
- git
- 前端
- thymeleaf
- 其他
- 代碼規范
- work_project
- Interview