前言
本文快速回顧了常考的的知識點,用作面試複習,事半功倍。
上篇主要內容為:虛擬機器資料區域,垃圾回收
下篇主要內容為:類載入機制
面試知識點複習手冊
全複習手冊文章導航
Csdn全複習手冊文章導航:blog.csdn.net/qqxx6661/ar…
已釋出知識點複習手冊
- Java基礎知識點面試手冊
- 快速梳理23種常用的設計模式
- Redis基礎知識點面試手冊
- Java容器(List、Set、Map)知識點快速複習手冊
- Java併發知識點快速複習手冊(上)
- Java併發知識點快速複習手冊(下)
- Java虛擬機器知識點快速複習手冊(上)
- Java虛擬機器知識點快速複習手冊(下)
參考
本文內容參考自CyC2018的Github倉庫:CS-Notes
有刪減,修改,補充額外增加內容
其他參考文章:
-
微信文章:精華:Java 開發崗面試知識點解析
本作品採用知識共享署名-非商業性使用 4.0 國際許可協議進行許可。
資料區域
此為1.6圖例:
程式計數器
記錄正在執行的虛擬機器位元組碼指令的地址(如果正在執行的是本地方法則為空)。
虛擬機器棧
存放區域性變數,由宣告在某方法,或某程式碼段裡(比如for迴圈),執行到它的時候在棧中開闢記憶體,當區域性變數一但脫離作用域,記憶體立即釋放
每個 Java 方法在執行的同時會建立一個棧幀用於儲存區域性變數表、運算元棧、常量池引用等資訊。每一個方法從呼叫直至執行完成的過程,就對應著一個棧幀在 Java 虛擬機器棧中入棧和出棧的過程。
可以通過 -Xss 這個虛擬機器引數來指定一個程式的 Java 虛擬機器棧記憶體大小:
java -Xss=512M HackTheJava
複製程式碼
該區域可能丟擲以下異常:
- 當執行緒請求的棧深度超過最大值,會丟擲 StackOverflowError 異常;
- 棧進行動態擴充套件時如果無法申請到足夠記憶體,會丟擲 OutOfMemoryError 異常。
本地方法棧
本地方法不是用 Java實現,對待這些方法需要特別處理。
堆
所有物件例項都在這裡分配記憶體。
因此虛擬機器把 Java 堆分成以下三塊:
- 新生代(Young Generation)
- 老年代(Old Generation)
- 永久代(Permanent Generation)(JDK1.7永久代才在堆中,1.6中被稱為執行時常量池。JDK 1.8 之後,取消了永久代,變為虛擬機器之外的元空間)
關於元空間詳細說明,請看Java-基礎面試題整合版-java8的新特性
可以通過 -Xms 和 -Xmx 兩個虛擬機器引數來指定一個程式的 Java 堆記憶體大小,第一個引數設定初始值,第二個引數設定最大值。
java -Xms=1M -Xmx=2M HackTheJava
複製程式碼
預設空餘堆記憶體小於 40% 時,JVM 就會增大堆直到-Xmx 的最大限制;
空餘堆記憶體大於 70% 時,JVM 會減少堆直到 -Xms 的最小限制;
伺服器一般設定-Xms、-Xmx 相等以避免在每次 GC 後調整堆的大小。
方法區
用於存放已被載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。
和 Java 堆一樣不需要連續的記憶體,並且可以動態擴充套件,動態擴充套件失敗一樣會丟擲 OutOfMemoryError 異常。
對這塊區域進行垃圾回收的主要目標是對常量池的回收和對類的解除安裝,但是一般比較難實現。
JDK 1.7 之前,HotSpot 虛擬機器把它當成永久代來進行垃圾回收,JDK 1.8 之後,取消了永久代,用 metaspace(後設資料)區替代。
執行時常量池
執行時常量池是方法區的一部分。
Class 檔案中的常量池(編譯器生成的各種字面量和符號引用)會在類載入後被放入這個區域。
除了在編譯期生成的常量,還允許動態生成,例如 String 類的 intern()。這部分常量也會被放入執行時常量池。
直接記憶體
在 JDK 1.4 中新加入了 NIO (傳統的IO又稱BIO,即阻塞式IO,NIO就是非阻塞IO了。AIO就是非同步IO)類,它可以使用 Native 函式庫直接分配堆外記憶體,然後通過一個儲存在 Java 堆裡的 DirectByteBuffer 物件作為這塊記憶體的引用進行操作。這樣能在一些場景中顯著提高效能,因為避免了在 Java 堆和 Native 堆中來回複製資料。
垃圾回收
程式計數器、虛擬機器棧和本地方法棧這三個區域屬於執行緒私有的,只存在於執行緒的生命週期內,執行緒結束之後也會消失,因此不需要對這三個區域進行垃圾回收。
垃圾回收主要是針對 Java 堆和方法區進行。
判斷一個物件是否可回收
1. 引用計數演算法
給物件新增一個引用計數器,當物件增加一個引用時計數器加 1,引用失效時計數器減 1。引用計數為 0 的物件可被回收。
兩個物件出現迴圈引用的情況下,此時引用計數器永遠不為 0,導致無法對它們進行回收。
public class ReferenceCountingGC {
public Object instance = null;
public static void main(String[] args) {
ReferenceCountingGC objectA = new ReferenceCountingGC();
ReferenceCountingGC objectB = new ReferenceCountingGC();
objectA.instance = objectB;
objectB.instance = objectA;
}
}
複製程式碼
正因為迴圈引用的存在,因此 Java 虛擬機器不適用引用計數演算法。
2. 可達性分析演算法
通過 GC Roots 作為起始點進行搜尋,能夠到達到的物件都是存活的,不可達的物件可被回收。
在 Java 中 GC Roots 一般包含以下內容:
- 虛擬機器棧中引用的物件
- 本地方法棧中引用的物件
- 方法區中類靜態屬性引用的物件
- 方法區中的常量引用的物件
3. 引用型別
無論是通過引用計算演算法判斷物件的引用數量,還是通過可達性分析演算法判斷物件的引用鏈是否可達,判定物件是否可被回收都與引用有關。
Java 具有四種強度不同的引用型別。
(一)強引用
被強引用關聯的物件不會被垃圾收集器回收。
使用 new 一個新物件的方式來建立強引用。
Object obj = new Object();
複製程式碼
(二)軟引用
被軟引用關聯的物件,只有在記憶體不夠的情況下才會被回收。
使用 SoftReference 類來建立軟引用。
(三)弱引用
被弱引用關聯的物件一定會被垃圾收集器回收,也就是說它只能存活到下一次垃圾收集發生之前。
-
使用 WeakReference 類來實現弱引用。
WeakHashMap 的 Entry 繼承自 WeakReference,主要用來實現快取。
Tomcat 中的 ConcurrentCache 就使用了 WeakHashMap 來實現快取功能。ConcurrentCache 採取的是分代快取,經常使用的物件放入 eden 中,而不常用的物件放入 longterm。
eden 使用 ConcurrentHashMap 實現,longterm 使用 WeakHashMap,保證了不常使用的物件容易被回收。
(四)虛引用
又稱為幽靈引用或者幻影引用。一個物件是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用取得一個物件例項。
為一個物件設定虛引用關聯的唯一目的就是能在這個物件被收集器回收時收到一個系統通知。
使用 PhantomReference 來實現虛引用。
4. 方法區的回收
因為方法區主要存放永久代物件,而永久代物件的回收率比新生代差很多,因此在方法區上進行回收價效比不高。
主要是對常量池的回收和對類的解除安裝。
類的解除安裝條件很多,需要滿足以下三個條件,並且滿足了也不一定會被解除安裝:
- 該類所有的例項都已經被回收,也就是 Java 堆中不存在該類的任何例項。
- 載入該類的 ClassLoader 已經被回收。
- 該類對應的 java.lang.Class物件沒有在任何地方被引用,也就無法在任何地方通過反射訪問該類方法。
可以通過 -Xnoclassgc 引數來控制是否對類進行解除安裝。
在大量使用反射、動態代理、CGLib 等 ByteCode 框架、動態生成 JSP 以及 OSGi 這類頻繁自定義 ClassLoader 的場景都需要虛擬機器具備類解除安裝功能,以保證不會出現記憶體溢位。
5. finalize()
finalize() 類似 C++ 的解構函式,用來做關閉外部資源等工作。但是 try-finally 等方式可以做的更好,並且該方法執行代價高昂,不確定性大,無法保證各個物件的呼叫順序,因此最好不要使用。
當一個物件可被回收時,如果需要執行該物件的 finalize() 方法,那麼就有可能通過在該方法中讓物件重新被引用,從而實現自救。
垃圾收集演算法
1. 標記 - 清除
將需要回收的物件進行標記,然後清理掉被標記的物件。
不足:
- 標記和清除過程效率都不高;
- 會產生大量不連續的記憶體碎片,導致無法給大物件分配記憶體。
2. 標記 - 整理
讓所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體。
3. 複製
將記憶體劃分為大小相等的兩塊,每次只使用其中一塊,當這一塊記憶體用完了就將還存活的物件複製到另一塊上面,然後再把使用過的記憶體空間進行一次清理。
主要不足是隻使用了記憶體的一半。
現在的商業虛擬機器都採用複製演算法來回收新生代,但是並不是將記憶體劃分為大小相等的兩塊,而是分為一塊較大的 Eden 空間和兩塊較小的 Survior 空間,每次使用 Eden 空間和其中一塊 Survivor。
在回收時,將 Eden 和 Survivor 中還存活著的物件一次性複製到另一塊 Survivor 空間上,最後清理 Eden 和使用過的那一塊 Survivor。
HotSpot 虛擬機器的 Eden 和 Survivor 的大小比例預設為 8:1(8:1:1),保證了記憶體的利用率達到 90 %。(證明了只往eden區放新物件)
如果每次回收有多於 10% 的物件存活,那麼一塊 Survivor 空間就不夠用了,此時需要依賴於老年代進行分配擔保,也就是借用老年代的空間儲存放不下的物件。
4. 分代收集
現在的商業虛擬機器採用分代收集演算法,它根據物件存活週期將記憶體劃分為幾塊,不同塊採用適當的收集演算法。
一般將 Java 堆分為新生代和老年代。
- 新生代使用:複製演算法
- 老年代使用:標記 - 清理 或者 標記 - 整理 演算法
垃圾收集器
以上是 HotSpot 虛擬機器中的 7 個垃圾收集器,連線表示垃圾收集器可以配合使用。
1. Serial 收集器
Serial 翻譯為序列,可以理解為垃圾收集和使用者程式交替執行,這意味著在執行垃圾收集的時候需要停頓使用者程式。除了 CMS 和 G1 之外,其它收集器都是以序列的方式執行。CMS 和 G1 可以使得垃圾收集和使用者程式同時執行,被稱為併發執行。
它是單執行緒的收集器,只會使用一個執行緒進行垃圾收集工作。
它的優點是簡單高效,對於單個 CPU 環境來說,由於沒有執行緒互動的開銷,因此擁有最高的單執行緒收集效率。
它是 Client 模式下的預設新生代收集器,因為在使用者的桌面應用場景下,分配給虛擬機器管理的記憶體一般來說不會很大。Serial 收集器收集幾十兆甚至一兩百兆的新生代停頓時間可以控制在一百多毫秒以內,只要不是太頻繁,這點停頓是可以接受的。
2. ParNew 收集器
它是 Serial 收集器的多執行緒版本。
是 Server 模式下的虛擬機器首選新生代收集器,除了效能原因外,主要是因為除了 Serial 收集器,只有它能與 CMS 收集器配合工作。
預設開始的執行緒數量與 CPU 數量相同,可以使用 -XX:ParallelGCThreads 引數來設定執行緒數。
3. Parallel Scavenge 收集器
與 ParNew 一樣是多執行緒收集器。
其它收集器關注點是儘可能縮短垃圾收集時使用者執行緒的停頓時間,而它的目標是達到一個可控制的吞吐量,它被稱為“吞吐量優先”收集器。這裡的吞吐量指 CPU 用於執行使用者程式碼的時間佔總時間的比值。
停頓時間越短就越適合需要與使用者互動的程式,良好的響應速度能提升使用者體驗。而高吞吐量則可以高效率地利用 CPU 時間,儘快完成程式的運算任務,主要適合在後臺運算而不需要太多互動的任務。
縮短停頓時間是以犧牲吞吐量和新生代空間來換取的:新生代空間變小,垃圾回收變得頻繁,導致吞吐量下降。
可以通過一個開關引數打卡 GC 自適應的調節策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 區的比例、晉升老年代物件年齡等細節引數了。虛擬機器會根據當前系統的執行情況收集效能監控資訊,動態調整這些引數以提供最合適的停頓時間或者最大的吞吐量,這種方式稱為 。
4. Serial Old 收集器
是 Serial 收集器的老年代版本,也是給 Client 模式下的虛擬機器使用。如果用在 Server 模式下,它有兩大用途:
- 在 JDK 1.5 以及之前版本(Parallel Old 誕生以前)中與 Parallel Scavenge 收集器搭配使用。
- 作為 CMS 收集器的後備預案,在併發收集發生 Concurrent Mode Failure 時使用。
5. Parallel Old 收集器
是 Parallel Scavenge 收集器的老年代版本。
在注重吞吐量以及 CPU 資源敏感的場合,都可以優先考慮 Parallel Scavenge 加 Parallel Old 收集器。
6. CMS 收集器
CMS(Concurrent Mark Sweep),Mark Sweep 指的是標記 - 清除演算法。
特點:併發收集、低停頓。併發指的是使用者執行緒和 GC 執行緒同時執行。
分為以下四個流程:
- 初始標記:僅僅只是標記一下 GC Roots 能直接關聯到的物件,速度很快,需要停頓。
- 併發標記:進行 GC Roots Tracing 的過程,它在整個回收過程中耗時最長,不需要停頓。
- 重新標記:為了修正併發標記期間因使用者程式繼續運作而導致標記產生變動的那一部分物件的標記記錄,需要停頓。
- 併發清除:不需要停頓。
在整個過程中耗時最長的併發標記和併發清除過程中,收集器執行緒都可以與使用者執行緒一起工作,不需要進行停頓。
具有以下缺點:
- 吞吐量低:低停頓時間是以犧牲吞吐量為代價的,導致 CPU 利用率不夠高。
- 無法處理浮動垃圾,可能出現 Concurrent Mode Failure。浮動垃圾是指併發清除階段由於使用者執行緒繼續執行而產生的垃圾,這部分垃圾只能到下一次 GC 時才能進行回收。由於浮動垃圾的存在,因此需要預留出一部分記憶體,意味著 CMS 收集不能像其它收集器那樣等待老年代快滿的時候再回收。可以使用 -XX:CMSInitiatingOccupancyFraction 來改變觸發 CMS 收集器工作的記憶體佔用百分,如果這個值設定的太大,導致預留的記憶體不夠存放浮動垃圾,就會出現 Concurrent Mode Failure,這時虛擬機器將臨時啟用 Serial Old 來替代 CMS。
- 標記 - 清除演算法導致的空間碎片,往往出現老年代空間剩餘,但無法找到足夠大連續空間來分配當前物件,不得不提前觸發一次 Full GC。
7. G1 收集器
G1(Garbage-First),它是一款面向服務端應用的垃圾收集器,在多 CPU 和大記憶體的場景下有很好的效能。HotSpot 開發團隊賦予它的使命是未來可以替換掉 CMS 收集器。
Java 堆被分為新生代、老年代和永久代,其它收集器進行收集的範圍都是整個新生代或者老生代,而 G1 可以直接對新生代和永久代一起回收。
G1 把堆劃分成多個大小相等的獨立區域(Region),新生代和老年代不再物理隔離。
通過引入 Region 的概念,從而將原來的一整塊記憶體空間劃分成多個的小空間,使得每個小空間可以單獨進行垃圾回收。這種劃分方法帶來了很大的靈活性,使得可預測的停頓時間模型成為可能。通過記錄每個 Region 垃圾回收時間以及回收所獲得的空間(這兩個值是通過過去回收的經驗獲得),並維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的 Region。
每個 Region 都有一個 Remembered Set,用來記錄該 Region 物件的引用物件所在的 Region。通過使用 Remembered Set,在做可達性分析的時候就可以避免全堆掃描。
如果不計算維護 Remembered Set 的操作,G1 收集器的運作大致可劃分為以下幾個步驟:
- 初始標記
- 併發標記
- 最終標記:為了修正在併發標記期間因使用者程式繼續運作而導致標記產生變動的那一部分標記記錄,虛擬機器將這段時間物件變化記錄線上程的 Remembered Set Logs 裡面,最終標記階段需要把 Remembered Set Logs 的資料合併到 Remembered Set 中。這階段需要停頓執行緒,但是可並行執行。
- 篩選回收:首先對各個 Region 中的回收價值和成本進行排序,根據使用者所期望的 GC 停頓是時間來制定回收計劃。此階段其實也可以做到與使用者程式一起併發執行,但是因為只回收一部分 Region,時間是使用者可控制的,而且停頓使用者執行緒將大幅度提高收集效率。
具備如下特點:
- 空間整合:整體來看是基於“標記 - 整理”演算法實現的收集器,從區域性(兩個 Region 之間)上來看是基於“複製”演算法實現的,這意味著執行期間不會產生記憶體空間碎片。
- 可預測的停頓:能讓使用者明確指定在一個長度為 M 毫秒的時間片段內,消耗在 GC 上的時間不得超過 N 毫秒。
更詳細內容請參考:Getting Started with the G1 Garbage Collector
8. 比較
收集器 | 序列/並行/併發 | 新生代/老年代 | 收集演算法 | 目標 | 適用場景 |
---|---|---|---|---|---|
Serial | 序列 | 新生代 | 複製 | 響應速度優先 | 單 CPU 環境下的 Client 模式 |
Serial Old | 序列 | 老年代 | 標記-整理 | 響應速度優先 | 單 CPU 環境下的 Client 模式、CMS 的後備預案 |
ParNew | 序列 + 並行 | 新生代 | 複製演算法 | 響應速度優先 | 多 CPU 環境時在 Server 模式下與 CMS 配合 |
Parallel Scavenge | 序列 + 並行 | 新生代 | 複製演算法 | 吞吐量優先 | 在後臺運算而不需要太多互動的任務 |
Parallel Old | 序列 + 並行 | 老年代 | 標記-整理 | 吞吐量優先 | 在後臺運算而不需要太多互動的任務 |
CMS | 並行 + 併發 | 老年代 | 標記-清除 | 響應速度優先 | 集中在網際網路站或 B/S 系統服務端上的 Java 應用 |
G1 | 並行 + 併發 | 新生代 + 老年代 | 標記-整理 + 複製演算法 | 響應速度優先 | 面向服務端應用,將來替換 CMS |
記憶體分配與回收策略
物件的記憶體分配,也就是在堆上分配。主要分配在新生代的 Eden 區上,少數情況下也可能直接分配在老年代中。
1. Minor GC 和 Full GC
- Minor GC:發生在新生代上,因為新生代物件存活時間很短,因此 Minor GC 會頻繁執行,執行的速度一般也會比較快。
- Full GC:發生在老年代上,老年代物件和新生代的相反,其存活時間長,因此 Full GC 很少執行,而且執行速度會比 Minor GC 慢很多。
2. 記憶體分配策略
(一)物件優先在 Eden 分配
大多數情況下,物件在新生代 Eden 區分配,當 Eden 區空間不夠時,發起 Minor GC。
(二)大物件直接進入老年代
大物件是指需要連續記憶體空間的物件,最典型的大物件是那種很長的字串以及陣列。
經常出現大物件會提前觸發垃圾收集以獲取足夠的連續空間分配給大物件。
-XX:PretenureSizeThreshold,大於此值的物件直接在老年代分配,避免在 Eden 區和 Survivor 區之間的大量記憶體複製。
(三)長期存活的物件進入老年代
為物件定義年齡計數器,物件在 Eden 出生並經過 Minor GC 依然存活,將移動到 Survivor 中,年齡就增加 1 歲,增加到一定年齡則移動到老年代中。預設15歲後就到年老代。
-XX:MaxTenuringThreshold 用來定義年齡的閾值。
(四)動態物件年齡判定
虛擬機器並不是永遠地要求物件的年齡必須達到 MaxTenuringThreshold 才能晉升老年代,如果在 Survivor 區中相同年齡所有物件大小的總和大於 Survivor 空間的一半,則年齡大於或等於該年齡的物件可以直接進入老年代,無需等到 MaxTenuringThreshold 中要求的年齡。
(五)空間分配擔保
在發生 Minor GC 之前,虛擬機器先檢查老年代最大可用的連續空間是否大於新生代所有物件總空間,如果條件成立的話,那麼 Minor GC 可以確認是安全的;如果不成立的話虛擬機器會檢視 HandlePromotionFailure 設定值是否允許擔保失敗。
如果允許那麼就會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代物件的平均大小,如果大於,將嘗試著進行一次 Minor GC,儘管這次 Minor GC 是有風險的;
如果小於,或者 HandlePromotionFailure 設定不允許冒險,那這時也要改為進行一次 Full GC。
3. Minor GC、Full GC 的觸發條件(如何避免Full GC)
針對如上條件進行避免
對於 Minor GC,其觸發條件非常簡單,當 Eden 區空間滿時,就將觸發一次 Minor GC。而 Full GC 則相對複雜,有以下條件:
(一)呼叫 System.gc()
只是建議虛擬機器執行 Full GC,但是虛擬機器不一定真正去執行。不建議使用這種方式,而是讓虛擬機器管理記憶體。可通過-XX:+ DisableExplicitGC來禁止RMI呼叫System.gc。
(二)老年代空間不足
老年代空間不足的常見場景為前文所講的大物件直接進入老年代、長期存活的物件進入老年代等。
(三)空間分配擔保失敗(不允許擔保時)
使用複製演算法的 Minor GC 需要老年代的記憶體空間作擔保,如果擔保失敗會執行一次 Full GC。具體內容請參考上面的第五小節。
(四)統計得到的Minor GC晉升到舊生代的平均大小大於老年代的剩餘空間(允許擔保時)
在進行Minor GC時,做了一個判斷,如果之前統計所得到的Minor GC晉升到舊生代的平均大小大於舊生代的剩餘空間,那麼就直接觸發Full GC。 例如程式第一次觸發Minor GC後,有6MB的物件晉升到舊生代,那麼當下一次Minor GC發生時,首先檢查舊生代的剩餘空間是否大於6MB,如果小於6MB,則執行Full GC。
(五)JDK 1.7 及以前的永久代空間不足
當系統中要載入的類、反射的類和呼叫的方法較多時,Permanet Generation可能會被佔滿,在未配置為採用CMS GC的情況下也會執行Full GC。如果經過Full GC仍然回收不了,那麼JVM會丟擲如下錯誤資訊: java.lang.OutOfMemoryError: PermGen space 為避免Perm Gen佔滿造成Full GC現象,可採用的方法為增大Perm Gen空間或轉為使用CMS GC。
(六)CMS GC時出現promotion failed和concurrent mode failure
GC精簡整理
新生代
-
採取複製演算法,在Minor GC之前,to survivor區域保持清空
-
物件儲存在Eden和from survivor區,minor GC執行時,Eden中的倖存物件會被複制到to Survivor(同時物件年齡會增加1)。
-
而from survivor區中的倖存物件會考慮物件年齡,如果年齡沒達到閾值,物件依然複製到to survivor中。
-
如果物件達到閾值那麼將被移到老年代。複製階段完成後,Eden和From倖存區中只儲存死物件,可以視為清空。
-
如果在複製過程中to倖存區被填滿了,剩餘的物件將被放到老年代。
-
最後,From survivor和to survivor會調換一下名字,下次Minor GC時,To survivor變為From Survivor。
年老和永久區垃圾收集
當年老代記憶體不足的話就會觸發垃圾收集,這個回收叫做FULL GC.
預設是佔用了68%後收集,可用引數-XX:CMSInitiatingOccupancyFraction=68自行設定。
GC調優
話題很大,詳細請參考:
GC調優三個維度
制定明確的GC效能指標。對所有效能監控和管理來說, 有三個維度是通用的:
Latency(響應時間/延遲)
GC的延遲指標由一般的延遲需求決定。延遲指標通常如下所述:
- 所有交易必須在10秒內得到響應
- 90%的訂單付款操作必須在3秒以內處理完成
- 推薦商品必須在 100 ms 內展示到使用者面前
有了正式的需求,下一步就是檢查暫停時間。有許多工具可以使用, 在接下來的 6. GC 調優(工具篇) 中會進行詳細的介紹, 在本節中我們通過檢視GC日誌, 檢查一下GC暫停的時間。
Throughput(吞吐量)
吞吐量和延遲指標有很大區別。當然兩者都是根據一般吞吐量需求而得出的。一般吞吐量需求(Generic requirements for throughput) 類似這樣:
- 解決方案每天必須處理 100萬個訂單
- 解決方案必須支援1000個登入使用者,同時在5-10秒內執行某個操作: A、B或C
- 每週對所有客戶進行統計,時間不能超過6小時,時間視窗為每週日晚12點到次日6點之間。
和延遲需求類似, GC調優也需要確定GC行為所消耗的總時間。每個系統能接受的時間不同, 一般來說, GC佔用的總時間比不能超過 10%。
Capacity(系統容量)
系統容量(Capacity)需求,是在達成吞吐量和延遲指標的情況下,對硬體環境的額外約束。這類需求大多是來源於計算資源或者預算方面的原因。例如:
- 系統必須能部署到小於512 MB記憶體的Android裝置上
- 系統必須部署在Amazon EC2例項上, 配置不得超過 c3.xlarge(4核8GB)。
- 每月的 Amazon EC2 賬單不得超過 $12,000
幾種GC調優工具
JMX API
JMX是獲取 JVM內部執行時狀態資訊 的標準API. 可以編寫程式程式碼, 通過 JMX API 來訪問本程式所在的JVM,也可以通過JMX客戶端執行(遠端)訪問。
最常見的 JMX客戶端是 JConsole 和 JVisualVM (可以安裝各種外掛,十分強大)。兩個工具都是標準JDK的一部分, 而且很容易使用. 如果使用的是 JDK 7u40 及更高版本, 還可以使用另一個工具: Java Mission Control( 大致翻譯為 Java控制中心, jmc.exe)。
jstat
GC日誌(GC logs)
等等
關注我
我是蠻三刀把刀,目前為後臺開發工程師。主要關注後臺開發,網路安全,Python爬蟲等技術。
來微信和我聊聊:yangzd1102
Github:github.com/qqxx6661
原創部落格主要內容
- 筆試面試複習知識點手冊
- Leetcode演算法題解析(前150題)
- 劍指offer演算法題解析
- Python爬蟲相關技術分析和實戰
- 後臺開發相關技術分析和實戰
同步更新以下部落格
1. Csdn
擁有專欄:Leetcode題解(Java/Python)、Python爬蟲開發
2. 知乎
擁有專欄:碼農面試助攻手冊
3. 掘金
4. 簡書
個人公眾號:Rude3Knife
如果文章對你有幫助,不妨收藏起來並轉發給您的朋友們~