---
title: JVM常è§é¢è¯é¢æ»ç»
description: JVMæ ¸å¿ç¥è¯ç¹ä¸é«é¢é¢è¯é¢ç²¾ç¼æ»ç»ï¼æ¶µçå
ååºåååãåå¾åæ¶ç®æ³ä¸æ¶éå¨ãç±»å è½½æºå¶ãåäº²å§æ´¾æ¨¡åãG1/ZGCå徿¶éå¨ãOutOfMemoryErrorææ¥ãHeap DumpåæãJVMæ§è½è°ä¼åæ°çï¼å«å¾è§£ä¸å®ææ¡ä¾ã
category: Java
tag:
- JVM
head:
- - meta
- name: keywords
content: JVMé¢è¯é¢,JVMå
ååºå,JVMåå¾åæ¶,ç±»å è½½æºå¶,åäº²å§æ´¾æ¨¡å,GCç®æ³,G1,ZGC,OutOfMemoryError,OOMææ¥,Heap Dump,JVMè°ä¼,JVMåæ°
---
è¿é¨åå
容æèª [JavaGuide](https://javaguide.cn/) ä¸é¢å ç¯æç« ä¸çéç¹ï¼
1. [Java å
ååºå详解](https://javaguide.cn/java/jvm/memory-area.html)
2. [JVM åå¾åæ¶è¯¦è§£](https://javaguide.cn/java/jvm/jvm-garbage-collection.html)
3. [ç±»æä»¶ç»æè¯¦è§£](https://javaguide.cn/java/jvm/class-file-structure.html)
4. [ç±»å è½½è¿ç¨è¯¦è§£](https://javaguide.cn/java/jvm/class-loading-process.html)
5. [ç±»å è½½å¨è¯¦è§£](https://javaguide.cn/java/jvm/classloader.html)
## Java å
ååºå
### âï¸Java å
ååºåï¼è¿è¡æ¶æ°æ®åºï¼çç»æ
Java èææºå¨æ§è¡ Java ç¨åºçè¿ç¨ä¸ä¼æå®ç®¡ççå
åååæè¥å¹²ä¸ªä¸åçæ°æ®åºåã
JDK 1.8 åä¹åççæ¬ç¥æä¸åï¼æä»¬è¿é以 JDK 1.7 å JDK 1.8 è¿ä¸¤ä¸ªçæ¬ä¸ºä¾ä»ç»ã
**JDK 1.7**ï¼

**JDK 1.8**ï¼

**线ç¨ç§æçï¼**
- ç¨åºè®¡æ°å¨
- èææºæ
- æ¬å°æ¹æ³æ
**线ç¨å
±äº«çï¼**
- å
- æ¹æ³åº
- ç´æ¥å
å (éè¿è¡æ¶æ°æ®åºçä¸é¨å)
Java èææºè§è对äºè¿è¡æ¶æ°æ®åºåçè§å®æ¯ç¸å½å®½æ¾çã以å 为ä¾ï¼å å¯ä»¥æ¯è¿ç»ç©ºé´ï¼ä¹å¯ä»¥ä¸è¿ç»ãå ç大å°å¯ä»¥åºå®ï¼ä¹å¯ä»¥å¨è¿è¡æ¶æéæ©å± ãèææºå®ç°è
å¯ä»¥ä½¿ç¨ä»»ä½åå¾åæ¶ç®æ³ç®¡çå ï¼çè³å®å
¨ä¸è¿è¡å徿¶é乿¯å¯ä»¥çã
### âï¸åªä¸ªåºåä¸ä¼åºç° OutOfMemoryErrorï¼
ç¨åºè®¡æ°å¨æ¯å¯ä¸ä¸ä¸ªä¸ä¼åºç° `OutOfMemoryError` çå
ååºåï¼å®ççå½å¨æéç线ç¨çå建èå建ï¼éç线ç¨çç»æèæ»äº¡ã
ç¨åºè®¡æ°å¨æ¯ä¸åè¾å°çå
å空é´ï¼å¯ä»¥ç使¯å½åçº¿ç¨ææ§è¡çåèç çè¡å·æç¤ºå¨ãåèç è§£éå¨å·¥ä½æ¶éè¿æ¹åè¿ä¸ªè®¡æ°å¨ç弿¥éåä¸ä¸æ¡éè¦æ§è¡çåèç æä»¤ï¼åæ¯ã循ç¯ã跳转ãå¼å¸¸å¤çãçº¿ç¨æ¢å¤çåè½é½éè¦ä¾èµè¿ä¸ªè®¡æ°å¨æ¥å®æã
å¦å¤ï¼ä¸ºäºçº¿ç¨åæ¢åè½æ¢å¤å°æ£ç¡®çæ§è¡ä½ç½®ï¼æ¯æ¡çº¿ç¨é½éè¦æä¸ä¸ªç¬ç«çç¨åºè®¡æ°å¨ï¼å线ç¨ä¹é´è®¡æ°å¨äºä¸å½±åï¼ç¬ç«åå¨ï¼æä»¬ç§°è¿ç±»å
ååºå为â线ç¨ç§æâçå
åã
ä»ä¸é¢çä»ç»ä¸æä»¬ç¥éäºç¨åºè®¡æ°å¨ä¸»è¦æä¸¤ä¸ªä½ç¨ï¼
- åèç è§£éå¨éè¿æ¹åç¨åºè®¡æ°å¨æ¥ä¾æ¬¡è¯»åæä»¤ï¼ä»èå®ç°ä»£ç çæµç¨æ§å¶ï¼å¦ï¼é¡ºåºæ§è¡ãéæ©ã循ç¯ãå¼å¸¸å¤çã
- å¨å¤çº¿ç¨çæ
åµä¸ï¼ç¨åºè®¡æ°å¨ç¨äºè®°å½å½åçº¿ç¨æ§è¡çä½ç½®ï¼ä»èå½çº¿ç¨è¢«åæ¢åæ¥çæ¶åè½å¤ç¥é该线ç¨ä¸æ¬¡è¿è¡å°åªå¿äºã
### âï¸åªäºæ
åµå¯è½åºç°å 溢åºï¼
å æº¢åºï¼ä¹å°±æ¯æä»¬å¸¸è¯´ç `OutOfMemoryError: Java heap space`ï¼æ¯ Java å¼åä¸é常常è§çä¸ç§ä¸¥éé误ãå®çæ ¹æ¬åå å°±æ¯ JVM å¨å°è¯ä¸ºæ°å¯¹è±¡åé
å
åæ¶ï¼å ä¸å·²ç»æ²¡æè¶³å¤çè¿ç»ç©ºé´äºï¼å¹¶ä¸ç»è¿åå¾åæ¶åï¼ä¹æ æ³è
¾åºè¶³å¤ç空é´ã
导è´å 溢åºçåºæ¯ä¸»è¦å¯ä»¥å为两类ï¼
1. **å
åæ³æ¼**ï¼å¯¹è±¡ç¨å®äºä½æ²¡è¢«éæ¾ï¼æ¯å¦ `static` éåæ éå¢é¿ã `ThreadLocal` 没è°ç¨ `remove()` ã
2. **å
åè¨è**ï¼çæ¶é´å
å建äºå¤ªå¤å¯¹è±¡ï¼æ¯å¦ä¸æ¬¡æ§ä»æ°æ®åºæ¥äºå ç¾ä¸æ¡æ°æ®å° List éï¼æè
ç´æ¥æä¸ä¸ªå¤§æä»¶æ´ä¸ªè¯»è¿å
åã
### ç¨åºè¿è¡ä¸æ å¯è½ä¼åºç°ä»ä¹é误ï¼
- **`StackOverFlowError`ï¼** 妿æ çå
å大å°ä¸å
è®¸å¨ææ©å±ï¼é£ä¹å½çº¿ç¨è¯·æ±æ çæ·±åº¦è¶
è¿å½å Java èææºæ çæå¤§æ·±åº¦çæ¶åï¼å°±æåº `StackOverFlowError` é误ã
- **`OutOfMemoryError`ï¼** 妿æ çå
å大å°å¯ä»¥å¨ææ©å±ï¼ é£ä¹å½èææºå¨å¨ææ©å±æ æ¶æ æ³ç³è¯·å°è¶³å¤çå
å空é´ï¼åæåº`OutOfMemoryError`å¼å¸¸ã

### å å
åçä½ç¨åç»æ
Java èææºæç®¡ççå
å䏿大çä¸åï¼Java å æ¯ææçº¿ç¨å
±äº«çä¸åå
ååºåï¼å¨èææºå¯å¨æ¶å建ã**æ¤å
ååºåçå¯ä¸ç®çå°±æ¯åæ¾å¯¹è±¡å®ä¾ï¼å 乿æç对象å®ä¾ä»¥åæ°ç»é½å¨è¿éåé
å
åã**
Java ä¸çä¸âå ä¹âææç对象é½å¨å ä¸åé
ï¼ä½æ¯ï¼éç JIT ç¼è¯å¨çåå±ä¸éé¸åæææ¯éæ¸æçï¼æ ä¸åé
ãæ éæ¿æ¢ä¼åææ¯å°ä¼å¯¼è´ä¸äºå¾®å¦çååï¼ææç对象é½åé
å°å ä¸ä¹æ¸æ¸åå¾ä¸é£ä¹âç»å¯¹âäºãä» JDK 1.7 å¼å§å·²ç»é»è®¤å¼å¯éé¸åæï¼å¦ææäºæ¹æ³ä¸ç对象å¼ç¨æ²¡æè¢«è¿åæè
æªè¢«å¤é¢ä½¿ç¨ï¼ä¹å°±æ¯æªéé¸åºå»ï¼ï¼é£ä¹å¯¹è±¡å¯ä»¥ç´æ¥å¨æ ä¸åé
å
åã
Java å æ¯å徿¶éå¨ç®¡çç主è¦åºåï¼å æ¤ä¹è¢«ç§°ä½ **GC å ï¼Garbage Collected Heapï¼**ãä»åå¾åæ¶çè§åº¦ï¼ç±äºç°å¨æ¶éå¨åºæ¬é½éç¨å代å徿¶éç®æ³ï¼æä»¥ Java å è¿å¯ä»¥ç»åä¸ºï¼æ°ç代åè年代ï¼åç»è´ä¸ç¹æï¼EdenãSurvivorãOld ç空é´ãè¿ä¸æ¥ååçç®çæ¯æ´å¥½å°åæ¶å
åï¼æè
æ´å¿«å°åé
å
åã
å¨ JDK 7 çæ¬å JDK 7 çæ¬ä¹åï¼å å
å被é常å为ä¸é¢ä¸é¨åï¼
1. æ°ç代å
å(Young Generation)
2. èç代(Old Generation)
3. æ°¸ä¹
代(Permanent Generation)
ä¸å¾æç¤ºç Eden åºã两个 Survivor åº S0 å S1 é½å±äºæ°ç代ï¼ä¸é´ä¸å±å±äºèå¹´ä»£ï¼æä¸é¢ä¸å±å±äºæ°¸ä¹
代ã

**JDK 8 çæ¬ä¹å PermGen(æ°¸ä¹
代) 已被 Metaspace(å
空é´) å代ï¼å
空é´ä½¿ç¨çæ¯æ¬å°å
åã** ï¼æä¼å¨æ¹æ³åºè¿é¨åå
容详ç»ä»ç»å°ï¼ã
大é¨åæ
åµï¼å¯¹è±¡é½ä¼é¦å
å¨ Eden åºååé
ï¼å¨ä¸æ¬¡æ°ç代åå¾åæ¶åï¼å¦æå¯¹è±¡è¿åæ´»ï¼åä¼è¿å
¥ S0 æè
S1ï¼å¹¶ä¸å¯¹è±¡çå¹´é¾è¿ä¼å 1(Eden åº->Survivor åºå对象çåå§å¹´é¾å为 1)ï¼å½å®çå¹´é¾å¢å å°ä¸å®ç¨åº¦ï¼é»è®¤ä¸º 15 å²ï¼ï¼å°±ä¼è¢«æåå°è年代ä¸ã对象æåå°è年代çå¹´é¾éå¼ï¼å¯ä»¥éè¿åæ° `-XX:MaxTenuringThreshold` æ¥è®¾ç½®ãä¸è¿ï¼è®¾ç½®çå¼åºè¯¥å¨ 0-15ï¼å¦åä¼çåºä»¥ä¸é误ï¼
```bash
MaxTenuringThreshold of 20 is invalid; must be between 0 and 15
```
### âï¸ç¨åºè¿è¡ä¸å å¯è½ä¼åºç°ä»ä¹é误ï¼
å è¿éæå®¹æåºç°çå°±æ¯ `OutOfMemoryError` é误ï¼å¹¶ä¸åºç°è¿ç§é误ä¹åç表ç°å½¢å¼è¿ä¼æå ç§ï¼æ¯å¦ï¼
1. **`java.lang.OutOfMemoryError: GC Overhead Limit Exceeded`**ï¼å½ JVM è±å¤ªå¤æ¶é´æ§è¡åå¾åæ¶å¹¶ä¸åªè½åæ¶å¾å°çå ç©ºé´æ¶ï¼å°±ä¼åçæ¤é误ã
2. **`java.lang.OutOfMemoryError: Java heap space`** :åå¦å¨å建æ°ç对象æ¶, å å
åä¸ç空é´ä¸è¶³ä»¥åæ¾æ°å建ç对象, å°±ä¼å¼åæ¤é误ã(åé
ç½®çæå¤§å å
åæå
³ï¼ä¸åå¶äºç©çå
å大å°ãæå¤§å å
åå¯éè¿`-Xmx`åæ°é
ç½®ï¼è¥æ²¡æç¹å«é
ç½®ï¼å°ä¼ä½¿ç¨é»è®¤å¼ï¼è¯¦è§ï¼[Default Java 8 max heap size](https://stackoverflow.com/questions/28272923/default-xmxsize-in-java-8-max-heap-size))
3. â¦â¦
### âï¸ä¸ºä»ä¹è¦å°æ°¸ä¹
代 (PermGen) æ¿æ¢ä¸ºå
ç©ºé´ (MetaSpace) å¢?
ä¸å¾æ¥èªãæ·±å
¥çè§£ Java èææºã第 3 ç 2.2.5

1ãæ´ä¸ªæ°¸ä¹
代æä¸ä¸ª JVM æ¬èº«è®¾ç½®çåºå®å¤§å°ä¸éï¼æ æ³è¿è¡è°æ´ï¼ä¹å°±æ¯åå° JVM å
åçéå¶ï¼ï¼èå
空é´ä½¿ç¨çæ¯æ¬å°å
åï¼åæ¬æºå¯ç¨å
åçéå¶ï¼è½ç¶å
空é´ä»æ§å¯è½æº¢åºï¼ä½æ¯æ¯åæ¥åºç°çå ç伿´å°ã
> å½å
ç©ºé´æº¢åºæ¶ä¼å¾å°å¦ä¸é误ï¼`java.lang.OutOfMemoryError: MetaSpace`
ä½ å¯ä»¥ä½¿ç¨ `-XXï¼MaxMetaspaceSize` æ å¿è®¾ç½®æå¤§å
空é´å¤§å°ï¼é»è®¤å¼ä¸º unlimitedï¼è¿æå³çå®åªåç³»ç»å
åçéå¶ã`-XXï¼MetaspaceSize` è°æ´æ å¿å®ä¹å
空é´çåå§å¤§å°å¦ææªæå®æ¤æ å¿ï¼å Metaspace å°æ ¹æ®è¿è¡æ¶çåºç¨ç¨åºéæ±å¨æå°éæ°è°æ´å¤§å°ã
2ãå
空é´éé¢åæ¾çæ¯ç±»çå
æ°æ®ï¼è¿æ ·å è½½å¤å°ç±»çå
æ°æ®å°±ä¸ç± `MaxPermSize` æ§å¶äº, èç±ç³»ç»çå®é
å¯ç¨ç©ºé´æ¥æ§å¶ï¼è¿æ ·è½å è½½ç类就æ´å¤äºã
3ãå¨ JDK8ï¼åå¹¶ HotSpot å JRockit çä»£ç æ¶, JRockit 仿¥æ²¡æä¸ä¸ªå«æ°¸ä¹
代çä¸è¥¿, åå¹¶ä¹å就没æå¿
è¦é¢å¤ç设置è¿ä¹ä¸ä¸ªæ°¸ä¹
代çå°æ¹äºã
4ãæ°¸ä¹
代ä¼ä¸º GC 带æ¥ä¸å¿
è¦çå¤æåº¦ï¼å¹¶ä¸åæ¶æçåä½ã
### æ¹æ³åºå¸¸ç¨åæ°æåªäºï¼
JDK 1.8 ä¹åæ°¸ä¹
ä»£è¿æ²¡è¢«å½»åºç§»é¤çæ¶åé常éè¿ä¸é¢è¿äºåæ°æ¥è°èæ¹æ³åºå¤§å°ã
```java
-XX:PermSize=N //æ¹æ³åº (æ°¸ä¹
代) åå§å¤§å°
-XX:MaxPermSize=N //æ¹æ³åº (æ°¸ä¹
代) æå¤§å¤§å°,è¶
è¿è¿ä¸ªå¼å°ä¼æåº OutOfMemoryError å¼å¸¸:java.lang.OutOfMemoryError: PermGen
```
ç¸å¯¹èè¨ï¼å徿¶éè¡ä¸ºå¨è¿ä¸ªåºåæ¯æ¯è¾å°åºç°çï¼ä½å¹¶éæ°æ®è¿å
¥æ¹æ³åºåå°±âæ°¸ä¹
åå¨âäºã
JDK 1.8 çæ¶åï¼æ¹æ³åºï¼HotSpot çæ°¸ä¹
代ï¼è¢«å½»åºç§»é¤äºï¼JDK1.7 就已ç»å¼å§äºï¼ï¼åè代乿¯å
空é´ï¼å
空é´ä½¿ç¨çæ¯æ¬å°å
åãä¸é¢æ¯ä¸äºå¸¸ç¨åæ°ï¼
```java
-XX:MetaspaceSize=N //设置 Metaspace çåå§ï¼åæå°å¤§å°ï¼
-XX:MaxMetaspaceSize=N //设置 Metaspace çæå¤§å¤§å°
```
䏿°¸ä¹
代å¾å¤§çä¸åå°±æ¯ï¼å¦æä¸æå®å¤§å°çè¯ï¼éçæ´å¤ç±»çå建ï¼èææºä¼èå°½ææå¯ç¨çç³»ç»å
åã
### âï¸åç¬¦ä¸²å¸¸éæ± çä½ç¨æ¯ï¼
**åç¬¦ä¸²å¸¸éæ± ** æ¯ JVM ä¸ºäºæåæ§è½ååå°å
åæ¶èé对å符串ï¼String ç±»ï¼ä¸é¨å¼è¾çä¸ååºåï¼ä¸»è¦ç®çæ¯ä¸ºäºé¿å
å符串çéå¤å建ã
```java
// å¨åç¬¦ä¸²å¸¸éæ± ä¸å建å符串对象 âabâ
// å°å符串对象 âabâ çå¼ç¨èµå¼ç»ç» aa
String aa = "ab";
// ç´æ¥è¿ååç¬¦ä¸²å¸¸éæ± ä¸å符串对象 âabâï¼èµå¼ç»å¼ç¨ bb
String bb = "ab";
System.out.println(aa==bb); // true
```
HotSpot èææºä¸åç¬¦ä¸²å¸¸éæ± çå®ç°æ¯ `src/hotspot/share/classfile/stringTable.cpp` ,`StringTable` å¯ä»¥ç®åç解为ä¸ä¸ªåºå®å¤§å°ç`HashTable` ï¼å®¹é为 `StringTableSize`ï¼å¯ä»¥éè¿ `-XX:StringTableSize` åæ°æ¥è®¾ç½®ï¼ï¼ä¿åçæ¯å符串ï¼keyï¼å å符串对象çå¼ç¨ï¼valueï¼çæ å°å
³ç³»ï¼å符串对象çå¼ç¨æåå ä¸çå符串对象ã
JDK1.7 ä¹åï¼åç¬¦ä¸²å¸¸éæ± 忾卿°¸ä¹
代ãJDK1.7 åç¬¦ä¸²å¸¸éæ± åéæåé仿°¸ä¹
代移å¨å°äº Java å ä¸ã


### JDK 1.7 为ä»ä¹è¦å°åç¬¦ä¸²å¸¸éæ± ç§»å¨å°å ä¸ï¼
ä¸»è¦æ¯å 为永ä¹
ä»£ï¼æ¹æ³åºå®ç°ï¼ç GC åæ¶æç太ä½ï¼åªæå¨æ´å æ¶é (Full GC)çæ¶åæä¼è¢«æ§è¡ GCãJava ç¨åºä¸é叏伿大éç被å建çå符串çå¾
åæ¶ï¼å°åç¬¦ä¸²å¸¸éæ± æ¾å°å ä¸ï¼è½å¤æ´é«æåæ¶å°åæ¶å符串å
åã
### ç´æ¥å
åçä½ç¨æ¯ï¼
ç´æ¥å
忝ä¸ç§ç¹æ®çå
åç¼å²åºï¼å¹¶ä¸å¨ Java å ææ¹æ³åºä¸åé
çï¼èæ¯éè¿ JNI çæ¹å¼å¨æ¬å°å
åä¸åé
çã
ç´æ¥å
å并䏿¯èææºè¿è¡æ¶æ°æ®åºçä¸é¨åï¼ä¹ä¸æ¯èææºè§èä¸å®ä¹çå
ååºåï¼ä½æ¯è¿é¨åå
åä¹è¢«é¢ç¹å°ä½¿ç¨ãèä¸ä¹å¯è½å¯¼è´ `OutOfMemoryError` é误åºç°ã
JDK1.4 䏿°å å
¥ç **NIOï¼Non-Blocking I/Oï¼ä¹è¢«ç§°ä¸º New I/Oï¼**ï¼å¼å
¥äºä¸ç§åºäº**ééï¼Channelï¼**ä¸**ç¼ååºï¼Bufferï¼**ç I/O æ¹å¼ï¼å®å¯ä»¥ç´æ¥ä½¿ç¨ Native 彿°åºç´æ¥åé
å å¤å
åï¼ç¶åéè¿ä¸ä¸ªåå¨å¨ Java å ä¸ç DirectByteBuffer 对象ä½ä¸ºè¿åå
åçå¼ç¨è¿è¡æä½ãè¿æ ·å°±è½å¨ä¸äºåºæ¯ä¸æ¾èæé«æ§è½ï¼å 为**é¿å
äºå¨ Java å å Native å ä¹é´æ¥åå¤å¶æ°æ®**ã
ç´æ¥å
åçåé
ä¸ä¼åå° Java å çéå¶ï¼ä½æ¯ï¼æ¢ç¶æ¯å
åå°±ä¼åå°æ¬æºæ»å
å大å°ä»¥åå¤çå¨å¯»å空é´çéå¶ã
ç±»ä¼¼çæ¦å¿µè¿æ **å å¤å
å** ãå¨ä¸äºæç« ä¸å°ç´æ¥å
åçä»·äºå å¤å
åï¼ä¸ªäººè§å¾ä¸æ¯ç¹å«åç¡®ã
å å¤å
åå°±æ¯æå
å对象åé
å¨å å¤çå
åï¼è¿äºå
åç´æ¥åæä½ç³»ç»ç®¡çï¼è䏿¯èææºï¼ï¼è¿æ ·åçç»æå°±æ¯è½å¤å¨ä¸å®ç¨åº¦ä¸åå°åå¾åæ¶å¯¹åºç¨ç¨åºé æçå½±åã
### Java 对象çå建è¿ç¨
JVMï¼HotSpot èææºï¼ä¸å¯¹è±¡çå建è¿ç¨ä¸»è¦å为以ä¸äºæ¥ï¼
1. **ç±»å è½½æ£æ¥**ï¼èææºæ§è¡ new æä»¤æ¶ï¼å
æ£æ¥å¸¸éæ± ä¸å¯¹åºç±»ç符å·å¼ç¨æ¯å¦å·²å è½½ãè§£æååå§åï¼æªå®æåå
æ§è¡ç±»å è½½è¿ç¨ã
2. **åé
å
å**ï¼ç±»å è½½éè¿åï¼æ ¹æ®ç±»å 载确å®ç对象大å°ä» Java å ååå
åï¼åé
æ¹å¼æ âæé碰æâï¼éç¨äºå å
åè§æ´ï¼å¦ Serial/ParNew æ¶éå¨ï¼å â空é²å表âï¼éç¨äºå å
åä¸è§æ´ï¼å¦ CMS æ¶éå¨ï¼ï¼ä¸ºä¿è¯çº¿ç¨å®å
¨ï¼éç¨ CAS + 失败éè¯æ TLABï¼çº¿ç¨æ¬å°åé
ç¼å²ï¼æºå¶ã
3. **åå§åé¶å¼**ï¼å°åé
çå
å空é´ï¼é¤å¯¹è±¡å¤´å¤ï¼åå§å为é¶å¼ï¼ç¡®ä¿ Java 代ç 䏿ªèµåå§å¼çå®ä¾å段å¯ç´æ¥ä½¿ç¨å¯¹åºç±»åçé¶å¼ã
4. **设置对象头**ï¼å¨å¯¹è±¡å¤´ä¸è®°å½ç±»å
æ°æ®ä¿¡æ¯ãåå¸ç ãGC å代年é¾ãéç¶æçå¿
è¦ä¿¡æ¯ï¼å
·ä½è®¾ç½®ä¾èææºè¿è¡ç¶æï¼å¦æ¯å¦å¯ç¨ååéï¼èå®ã
5. **æ§è¡ init æ¹æ³**ï¼èææºè§è§ä¸å¯¹è±¡å·²å建ï¼ä½éæ§è¡``æ¹æ³æç¨åºåå®ä¹å®æåå§åï¼æç»çæå¯ç¨å¯¹è±¡ã
### âï¸å¯¹è±¡è®¿é®å®ä½çæ¹å¼æåªäºï¼
建ç«å¯¹è±¡å°±æ¯ä¸ºäºä½¿ç¨å¯¹è±¡ï¼æä»¬ç Java ç¨åºéè¿æ ä¸ç reference æ°æ®æ¥æä½å ä¸çå
·ä½å¯¹è±¡ã对象çè®¿é®æ¹å¼ç±èææºå®ç°èå®ï¼ç®å主æµçè®¿é®æ¹å¼æï¼**使ç¨å¥æ**ã**ç´æ¥æé**ã
#### 奿
å¦æä½¿ç¨å¥æçè¯ï¼é£ä¹ Java å ä¸å°ä¼åååºä¸åå
忥ä½ä¸ºå¥ææ± ï¼reference ä¸åå¨çå°±æ¯å¯¹è±¡ç奿å°åï¼è奿ä¸å
å«äºå¯¹è±¡å®ä¾æ°æ®ä¸å¯¹è±¡ç±»åæ°æ®åèªçå
·ä½å°åä¿¡æ¯ã

#### ç´æ¥æé
å¦æä½¿ç¨ç´æ¥æé访é®ï¼reference ä¸åå¨çç´æ¥å°±æ¯å¯¹è±¡çå°åã

è¿ä¸¤ç§å¯¹è±¡è®¿é®æ¹å¼åæä¼å¿ã使ç¨å¥ææ¥è®¿é®çæå¤§å¥½å¤æ¯ reference ä¸åå¨çæ¯ç¨³å®ç奿å°åï¼å¨å¯¹è±¡è¢«ç§»å¨æ¶åªä¼æ¹å奿ä¸çå®ä¾æ°æ®æéï¼è reference æ¬èº«ä¸éè¦ä¿®æ¹ã使ç¨ç´æ¥æéè®¿é®æ¹å¼æå¤§ç好å¤å°±æ¯é度快ï¼å®èçäºä¸æ¬¡æéå®ä½çæ¶é´å¼éã
HotSpot èææºä¸»è¦ä½¿ç¨çå°±æ¯è¿ç§æ¹å¼æ¥è¿è¡å¯¹è±¡è®¿é®ã
## JVM åå¾åæ¶
### âï¸å¦ä½å¤æå¯¹è±¡æ¯å¦æ»äº¡
å ä¸å 乿¾çææç对象å®ä¾ï¼å¯¹å åå¾åæ¶åçç¬¬ä¸æ¥å°±æ¯è¦å¤æåªäºå¯¹è±¡å·²ç»æ»äº¡ï¼å³ä¸è½å被任ä½éå¾ä½¿ç¨ç对象ï¼ã
#### å¼ç¨è®¡æ°æ³
ç»å¯¹è±¡ä¸æ·»å ä¸ä¸ªå¼ç¨è®¡æ°å¨ï¼
- æ¯å½æä¸ä¸ªå°æ¹å¼ç¨å®ï¼è®¡æ°å¨å°±å 1ï¼
- å½å¼ç¨å¤±æï¼è®¡æ°å¨å°±å 1ï¼
- 任使¶å计æ°å¨ä¸º 0 ç对象就æ¯ä¸å¯è½å被使ç¨çã
**è¿ä¸ªæ¹æ³å®ç°ç®åï¼æçé«ï¼ä½æ¯ç®å主æµçèææºä¸å¹¶æ²¡æéæ©è¿ä¸ªç®æ³æ¥ç®¡çå
åï¼å
¶æä¸»è¦çåå æ¯å®å¾é¾è§£å³å¯¹è±¡ä¹é´å¾ªç¯å¼ç¨çé®é¢ã**

æè°å¯¹è±¡ä¹é´çç¸äºå¼ç¨é®é¢ï¼å¦ä¸é¢ä»£ç æç¤ºï¼é¤äºå¯¹è±¡ `objA` å `objB` ç¸äºå¼ç¨ç对æ¹ä¹å¤ï¼è¿ä¸¤ä¸ªå¯¹è±¡ä¹é´åæ ä»»ä½å¼ç¨ã使¯ä»ä»¬å 为äºç¸å¼ç¨å¯¹æ¹ï¼å¯¼è´å®ä»¬çå¼ç¨è®¡æ°å¨é½ä¸ä¸º 0ï¼äºæ¯å¼ç¨è®¡æ°ç®æ³æ æ³éç¥ GC åæ¶å¨åæ¶ä»ä»¬ã
```java
public class ReferenceCountingGc {
Object instance = null;
public static void main(String[] args) {
ReferenceCountingGc objA = new ReferenceCountingGc();
ReferenceCountingGc objB = new ReferenceCountingGc();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
}
}
```
#### å¯è¾¾æ§åæç®æ³
è¿ä¸ªç®æ³çåºæ¬ææ³å°±æ¯éè¿ä¸ç³»åç称为 **âGC Rootsâ** ç对象ä½ä¸ºèµ·ç¹ï¼ä»è¿äºèç¹å¼å§åä¸æç´¢ï¼èç¹æèµ°è¿çè·¯å¾ç§°ä¸ºå¼ç¨é¾ï¼å½ä¸ä¸ªå¯¹è±¡å° GC Roots 没æä»»ä½å¼ç¨é¾ç¸è¿çè¯ï¼åè¯ææ¤å¯¹è±¡æ¯ä¸å¯ç¨çï¼éè¦è¢«åæ¶ã
ä¸å¾ä¸ç `Object 6 ~ Object 10` ä¹é´è½æå¼ç¨å
³ç³»ï¼ä½å®ä»¬å° GC Roots ä¸å¯è¾¾ï¼å æ¤ä¸ºéè¦è¢«åæ¶ç对象ã

**åªäºå¯¹è±¡å¯ä»¥ä½ä¸º GC Roots å¢ï¼**
- èææºæ (æ 帧ä¸çå±é¨åé表)ä¸å¼ç¨ç对象
- æ¬å°æ¹æ³æ (Native æ¹æ³)ä¸å¼ç¨ç对象
- æ¹æ³åºä¸ç±»éæå±æ§å¼ç¨ç对象
- æ¹æ³åºä¸å¸¸éå¼ç¨ç对象
- ææè¢«åæ¥éææç对象
- JNIï¼Java Native Interfaceï¼å¼ç¨ç对象
**对象å¯ä»¥è¢«åæ¶ï¼å°±ä»£è¡¨ä¸å®ä¼è¢«åæ¶åï¼**
å³ä½¿å¨å¯è¾¾æ§åææ³ä¸ä¸å¯è¾¾ç对象ï¼ä¹å¹¶éæ¯âéæ»ä¸å¯âçï¼è¿æ¶åå®ä»¬ææ¶å¤äºâç¼åé¶æ®µâï¼è¦çæ£å®£åä¸ä¸ªå¯¹è±¡æ»äº¡ï¼è³å°è¦ç»å两次æ è®°è¿ç¨ï¼å¯è¾¾æ§åææ³ä¸ä¸å¯è¾¾çå¯¹è±¡è¢«ç¬¬ä¸æ¬¡æ è®°å¹¶ä¸è¿è¡ä¸æ¬¡çéï¼çéçæ¡ä»¶æ¯æ¤å¯¹è±¡æ¯å¦æå¿
è¦æ§è¡ `finalize` æ¹æ³ãå½å¯¹è±¡æ²¡æè¦ç `finalize` æ¹æ³ï¼æ `finalize` æ¹æ³å·²ç»è¢«èææºè°ç¨è¿æ¶ï¼èææºå°è¿ä¸¤ç§æ
åµè§ä¸ºæ²¡æå¿
è¦æ§è¡ã
被å¤å®ä¸ºéè¦æ§è¡ç对象å°ä¼è¢«æ¾å¨ä¸ä¸ªéåä¸è¿è¡ç¬¬äºæ¬¡æ è®°ï¼é¤éè¿ä¸ªå¯¹è±¡ä¸å¼ç¨é¾ä¸çä»»ä½ä¸ä¸ªå¯¹è±¡å»ºç«å
³èï¼å¦åå°±ä¼è¢«ççåæ¶ã
> `Object` ç±»ä¸ç `finalize` æ¹æ³ä¸ç´è¢«è®¤ä¸ºæ¯ä¸ä¸ªç³ç³çè®¾è®¡ï¼æä¸ºäº Java è¯è¨çè´æ
ï¼å½±åäº Java è¯è¨çå®å
¨å GC çæ§è½ãJDK9 çæ¬ååç»çæ¬ä¸å个类ä¸ç `finalize` æ¹æ³ä¼è¢«éæ¸å¼ç¨ç§»é¤ãå¿æå®çåå¨å§ï¼
>
> åèï¼
>
> - [JEP 421: Deprecate Finalization for Removal](https://openjdk.java.net/jeps/421)
> - [æ¯æ¶åå¿æ finalize æ¹æ³äº](https://mp.weixin.qq.com/s/LW-paZAMD08DP_3-XCUxmg)
### 常è§çå¼ç¨ç±»åæåªäºï¼
æ 论æ¯éè¿å¼ç¨è®¡æ°æ³å¤æå¯¹è±¡å¼ç¨æ°éï¼è¿æ¯éè¿å¯è¾¾æ§åææ³å¤æå¯¹è±¡çå¼ç¨é¾æ¯å¦å¯è¾¾ï¼å¤å®å¯¹è±¡çåæ´»é½ä¸âå¼ç¨âæå
³ã
JDK1.2 ä¹åï¼Java ä¸å¼ç¨çå®ä¹å¾ä¼ ç»ï¼å¦æ reference ç±»åçæ°æ®åå¨çæ°å¼ä»£è¡¨çæ¯å¦ä¸åå
åçèµ·å§å°åï¼å°±ç§°è¿åå
å代表ä¸ä¸ªå¼ç¨ã
JDK1.2 以åï¼Java 对å¼ç¨çæ¦å¿µè¿è¡äºæ©å
ï¼å°å¼ç¨å为强å¼ç¨ã软å¼ç¨ãå¼±å¼ç¨ãèå¼ç¨åç§ï¼å¼ç¨å¼ºåº¦éæ¸åå¼±ï¼ï¼å¼ºå¼ç¨å°±æ¯ Java 䏿®éç对象ï¼è软å¼ç¨ãå¼±å¼ç¨ãèå¼ç¨å¨ JDK ä¸å®ä¹çç±»å嫿¯ `SoftReference`ã`WeakReference`ã`PhantomReference`ã

**1ï¼å¼ºå¼ç¨ï¼StrongReferenceï¼**
强å¼ç¨å®é
ä¸å°±æ¯ç¨åºä»£ç 䏿®éåå¨çå¼ç¨èµå¼ï¼è¿æ¯ä½¿ç¨ææ®éçå¼ç¨ï¼å
¶ä»£ç å¦ä¸
```java
String strongReference = new String("abc");
```
妿ä¸ä¸ªå¯¹è±¡å
·æå¼ºå¼ç¨ï¼é£å°±ç±»ä¼¼äº**å¿
ä¸å¯å°ççæ´»ç¨å**ï¼åå¾åæ¶å¨ç»ä¸ä¼åæ¶å®ãå½å
å空é´ä¸è¶³ï¼Java èææºå®æ¿æåº OutOfMemoryError é误ï¼ä½¿ç¨åºå¼å¸¸ç»æ¢ï¼ä¹ä¸ä¼é éæåæ¶å
·æå¼ºå¼ç¨ç对象æ¥è§£å³å
åä¸è¶³é®é¢ã
**2ï¼è½¯å¼ç¨ï¼SoftReferenceï¼**
妿ä¸ä¸ªå¯¹è±¡åªå
·æè½¯å¼ç¨ï¼é£å°±ç±»ä¼¼äº**坿坿 ççæ´»ç¨å**ã软å¼ç¨ä»£ç å¦ä¸
```java
// 软å¼ç¨
String str = new String("abc");
SoftReference softReference = new SoftReference(str);
```
妿å
å空é´è¶³å¤ï¼åå¾åæ¶å¨å°±ä¸ä¼åæ¶å®ï¼å¦æå
å空é´ä¸è¶³äºï¼å°±ä¼åæ¶è¿äºå¯¹è±¡çå
åãåªè¦åå¾åæ¶å¨æ²¡æåæ¶å®ï¼è¯¥å¯¹è±¡å°±å¯ä»¥è¢«ç¨åºä½¿ç¨ã软å¼ç¨å¯ç¨æ¥å®ç°å
åææçé«éç¼åã
软å¼ç¨å¯ä»¥åä¸ä¸ªå¼ç¨éåï¼ReferenceQueueï¼èå使ç¨ï¼å¦æè½¯å¼ç¨æå¼ç¨ç对象被åå¾åæ¶ï¼JAVA èææºå°±ä¼æè¿ä¸ªè½¯å¼ç¨å å
¥å°ä¸ä¹å
³èçå¼ç¨éåä¸ã
**3ï¼å¼±å¼ç¨ï¼WeakReferenceï¼**
妿ä¸ä¸ªå¯¹è±¡åªå
·æå¼±å¼ç¨ï¼é£å°±ç±»ä¼¼äº**坿坿 ççæ´»ç¨å**ãå¼±å¼ç¨ä»£ç å¦ä¸ï¼
```java
String str = new String("abc");
WeakReference weakReference = new WeakReference<>(str);
str = null; //stråæè½¯å¼ç¨ï¼å¯ä»¥è¢«æ¶é
```
å¼±å¼ç¨ä¸è½¯å¼ç¨çåºå«å¨äºï¼åªå
·æå¼±å¼ç¨çå¯¹è±¡æ¥ææ´çæççå½å¨æãå¨åå¾åæ¶å¨çº¿ç¨æ«æå®æç®¡è¾çå
ååºåçè¿ç¨ä¸ï¼ä¸æ¦åç°äºåªå
·æå¼±å¼ç¨ç对象ï¼ä¸ç®¡å½åå
å空é´è¶³å¤ä¸å¦ï¼é½ä¼åæ¶å®çå
åãä¸è¿ï¼ç±äºåå¾åæ¶å¨æ¯ä¸ä¸ªä¼å
级å¾ä½ç线ç¨ï¼ å æ¤ä¸ä¸å®ä¼å¾å¿«åç°é£äºåªå
·æå¼±å¼ç¨ç对象ã
å¼±å¼ç¨å¯ä»¥åä¸ä¸ªå¼ç¨éåï¼ReferenceQueueï¼èå使ç¨ï¼å¦æå¼±å¼ç¨æå¼ç¨ç对象被åå¾åæ¶ï¼Java èææºå°±ä¼æè¿ä¸ªå¼±å¼ç¨å å
¥å°ä¸ä¹å
³èçå¼ç¨éåä¸ã
**4ï¼èå¼ç¨ï¼PhantomReferenceï¼**
"èå¼ç¨"顾åæä¹ï¼å°±æ¯å½¢åè设ï¼ä¸å
¶ä»å ç§å¼ç¨é½ä¸åï¼èå¼ç¨å¹¶ä¸ä¼å³å®å¯¹è±¡ççå½å¨æã妿ä¸ä¸ªå¯¹è±¡ä»
ææèå¼ç¨ï¼é£ä¹å®å°±å没æä»»ä½å¼ç¨ä¸æ ·ï¼å¨ä»»ä½æ¶åé½å¯è½è¢«åå¾åæ¶ãèå¼ç¨ä»£ç å¦ä¸ï¼
```java
String str = new String("abc");
ReferenceQueue queue = new ReferenceQueue();
// å建èå¼ç¨ï¼è¦æ±å¿
é¡»ä¸ä¸ä¸ªå¼ç¨éåå
³è
PhantomReference pr = new PhantomReference(str, queue);
```
**èå¼ç¨ä¸»è¦ç¨æ¥è·è¸ªå¯¹è±¡è¢«åå¾åæ¶çæ´»å¨**ã
**èå¼ç¨ä¸è½¯å¼ç¨åå¼±å¼ç¨çä¸ä¸ªåºå«å¨äºï¼** èå¼ç¨å¿
é¡»åå¼ç¨éåï¼ReferenceQueueï¼èå使ç¨ãå½åå¾åæ¶å¨åå¤åæ¶ä¸ä¸ªå¯¹è±¡æ¶ï¼å¦æåç°å®è¿æèå¼ç¨ï¼å°±ä¼å¨åæ¶å¯¹è±¡çå
åä¹åï¼æè¿ä¸ªèå¼ç¨å å
¥å°ä¸ä¹å
³èçå¼ç¨éåä¸ãç¨åºå¯ä»¥éè¿å¤æå¼ç¨éå䏿¯å¦å·²ç»å å
¥äºèå¼ç¨ï¼æ¥äºè§£è¢«å¼ç¨ç对象æ¯å¦å°è¦è¢«åå¾åæ¶ãç¨åºå¦æåç°æä¸ªèå¼ç¨å·²ç»è¢«å å
¥å°å¼ç¨éåï¼é£ä¹å°±å¯ä»¥å¨æå¼ç¨ç对象çå
åè¢«åæ¶ä¹åéåå¿
è¦çè¡å¨ã
ç¹å«æ³¨æï¼å¨ç¨åºè®¾è®¡ä¸ä¸è¬å¾å°ä½¿ç¨å¼±å¼ç¨ä¸èå¼ç¨ï¼ä½¿ç¨è½¯å¼ç¨çæ
åµè¾å¤ï¼è¿æ¯å 为**软å¼ç¨å¯ä»¥å é JVM 对åå¾å
åçåæ¶é度ï¼å¯ä»¥ç»´æ¤ç³»ç»çè¿è¡å®å
¨ï¼é²æ¢å
åæº¢åºï¼OutOfMemoryï¼çé®é¢ç产ç**ã
### å¦ä½å¤æä¸ä¸ªç±»æ¯æ ç¨çç±»ï¼
æ¹æ³åºä¸»è¦åæ¶çæ¯æ ç¨çç±»ï¼é£ä¹å¦ä½å¤æä¸ä¸ªç±»æ¯æ ç¨çç±»çå¢ï¼
å¤å®ä¸ä¸ªå¸¸éæ¯å¦æ¯âåºå¼å¸¸éâæ¯è¾ç®åï¼èè¦å¤å®ä¸ä¸ªç±»æ¯å¦æ¯âæ ç¨çç±»âçæ¡ä»¶åç¸å¯¹èå»è®¸å¤ãç±»éè¦åæ¶æ»¡è¶³ä¸é¢ 3 个æ¡ä»¶æè½ç®æ¯ **âæ ç¨çç±»â**ï¼
- 该类ææçå®ä¾é½å·²ç»è¢«åæ¶ï¼ä¹å°±æ¯ Java å ä¸ä¸åå¨è¯¥ç±»çä»»ä½å®ä¾ã
- å 载该类ç `ClassLoader` å·²ç»è¢«åæ¶ã
- 该类对åºç `java.lang.Class` 对象没æå¨ä»»ä½å°æ¹è¢«å¼ç¨ï¼æ æ³å¨ä»»ä½å°æ¹éè¿åå°è®¿é®è¯¥ç±»çæ¹æ³ã
èææºå¯ä»¥å¯¹æ»¡è¶³ä¸è¿° 3 个æ¡ä»¶çæ ç¨ç±»è¿è¡åæ¶ï¼è¿é说çä»
ä»
æ¯âå¯ä»¥âï¼è并䏿¯åå¯¹è±¡ä¸æ ·ä¸ä½¿ç¨äºå°±ä¼å¿
ç¶è¢«åæ¶ã
### âï¸åå¾åæ¶ç®æ³æåªäºï¼
#### æ è®°-æ¸
é¤ç®æ³
æ è®°-æ¸
é¤ï¼Mark-and-Sweepï¼ç®æ³åä¸ºâæ è®°ï¼Markï¼âåâæ¸
é¤ï¼Sweepï¼âé¶æ®µï¼é¦å
æ è®°åºææä¸éè¦åæ¶ç对象ï¼å¨æ è®°å®æåç»ä¸åæ¶ææææ²¡æè¢«æ è®°ç对象ã
宿¯æåºç¡çæ¶éç®æ³ï¼åç»çç®æ³é½æ¯å¯¹å
¶ä¸è¶³è¿è¡æ¹è¿å¾å°ãè¿ç§å徿¶éç®æ³ä¼å¸¦æ¥ä¸¤ä¸ªææ¾çé®é¢ï¼
1. **æçé®é¢**ï¼æ è®°åæ¸
é¤ä¸¤ä¸ªè¿ç¨æçé½ä¸é«ã
2. **空é´é®é¢**ï¼æ è®°æ¸
é¤åä¼äº§ç大éä¸è¿ç»çå
åç¢çã

å
³äºå
·ä½æ¯æ è®°å¯åæ¶å¯¹è±¡è¿æ¯ä¸å¯åæ¶å¯¹è±¡ï¼ä¼è¯´çº·çºï¼ä¸¤ç§è¯´æ³å
¶å®é½æ²¡é®é¢ï¼æä¸ªäººæ´å¾åäºæ¯åè
ã
妿æç
§åè
ççè§£ï¼æ´ä¸ªæ è®°-æ¸
é¤è¿ç¨å¤§è´æ¯è¿æ ·çï¼
1. å½ä¸ä¸ªå¯¹è±¡è¢«å建æ¶ï¼ç»ä¸ä¸ªæ è®°ä½ï¼å设为 0 (false)ï¼
2. 卿 è®°é¶æ®µï¼æä»¬å°ææå¯è¾¾å¯¹è±¡ï¼æç¨æ·å¯ä»¥å¼ç¨ç对象ï¼çæ è®°ä½è®¾ç½®ä¸º 1 (true)ï¼
3. æ«æé¶æ®µæ¸
é¤çå°±æ¯æ è®°ä½ä¸º 0 (false)ç对象ã
#### å¤å¶ç®æ³
为äºè§£å³æ è®°-æ¸
é¤ç®æ³çæçåå
åç¢çé®é¢ï¼å¤å¶ï¼Copyingï¼æ¶éç®æ³åºç°äºãå®å¯ä»¥å°å
åå为大å°ç¸åç两åï¼æ¯æ¬¡ä½¿ç¨å
¶ä¸çä¸åãå½è¿ä¸åçå
å使ç¨å®åï¼å°±å°è¿åæ´»ç对象å¤å¶å°å¦ä¸åå»ï¼ç¶ååæä½¿ç¨ç空é´ä¸æ¬¡æ¸
çæãè¿æ ·å°±ä½¿æ¯æ¬¡çå
å忶齿¯å¯¹å
ååºé´çä¸åè¿è¡åæ¶ã

è½ç¶æ¹è¿äºæ è®°-æ¸
é¤ç®æ³ï¼ä½ä¾ç¶åå¨ä¸é¢è¿äºé®é¢ï¼
- **å¯ç¨å
ååå°**ï¼å¯ç¨å
å缩å°ä¸ºåæ¥çä¸åã
- **ä¸éåè年代**ï¼å¦æå活对象æ°éæ¯è¾å¤§ï¼å¤å¶æ§è½ä¼åå¾å¾å·®ã
#### æ è®°-æ´çç®æ³
æ è®°-æ´çï¼Mark-and-Compactï¼ç®æ³æ¯æ ¹æ®è年代çç¹ç¹æåºçä¸ç§æ è®°ç®æ³ï¼æ è®°è¿ç¨ä»ç¶ä¸âæ è®°-æ¸
é¤âç®æ³ä¸æ ·ï¼ä½åç»æ¥éª¤ä¸æ¯ç´æ¥å¯¹å¯åæ¶å¯¹è±¡åæ¶ï¼èæ¯è®©ææåæ´»ç对象åä¸ç«¯ç§»å¨ï¼ç¶åç´æ¥æ¸
çæç«¯è¾¹ç以å¤çå
åã

ç±äºå¤äºæ´çè¿ä¸æ¥ï¼å æ¤æçä¹ä¸é«ï¼éåè年代è¿ç§åå¾åæ¶é¢ç䏿¯å¾é«çåºæ¯ã
#### å代æ¶éç®æ³
å½åèææºçå徿¶éé½éç¨å代æ¶éç®æ³ï¼è¿ç§ç®æ³æ²¡æä»ä¹æ°çææ³ï¼åªæ¯æ ¹æ®å¯¹è±¡åæ´»å¨æçä¸åå°å
åå为å åãä¸è¬å° Java å å为æ°ç代åè年代ï¼è¿æ ·æä»¬å°±å¯ä»¥æ ¹æ®å个年代çç¹ç¹éæ©åéçå徿¶éç®æ³ã
æ¯å¦å¨æ°ç代ä¸ï¼æ¯æ¬¡æ¶éé½ä¼æå¤§é对象æ»å»ï¼æä»¥å¯ä»¥éæ©âæ è®°-å¤å¶âç®æ³ï¼åªéè¦ä»åºå°é对象çå¤å¶ææ¬å°±å¯ä»¥å®ææ¯æ¬¡å徿¶éãèè年代çå¯¹è±¡åæ´»å çæ¯æ¯è¾é«çï¼è䏿²¡æé¢å¤ç空é´å¯¹å®è¿è¡åé
æ
ä¿ï¼æä»¥æä»¬å¿
é¡»éæ©âæ è®°-æ¸
é¤âæâæ è®°-æ´çâç®æ³è¿è¡å徿¶éã
**延伸é¢è¯é®é¢ï¼** HotSpot 为ä»ä¹è¦å为æ°ç代åè年代ï¼
æ ¹æ®ä¸é¢ç对å代æ¶éç®æ³çä»ç»åçã
### âï¸JDK 1.8 çé»è®¤åå¾åæ¶å¨æ¯ï¼JDK1.9 ä¹åå¢ï¼
- **JDK 1.8 é»è®¤åå¾åæ¶å¨**ï¼Parallel Scanvengeï¼æ°ç代ï¼+ Parallel Oldï¼è年代ï¼ã è¿ä¸ªç»åä¹è¢«ç§°ä¸º Parallel GC æ Throughput GCï¼ä¾§éäºååéã
- **JDK 1.9 å以åé»è®¤åå¾åæ¶å¨**ï¼G1 GC (Garbage-First Garbage Collector)ã G1 GC æ¯ä¸ä¸ªæ´ç°ä»£åçåå¾åæ¶å¨ï¼æ¨å¨å¹³è¡¡ååéååé¡¿æ¶é´ï¼å°¤å
¶éç¨äºå å
åè¾å¤§çåºç¨ã
### âï¸G1 åå¾åæ¶çè¿ç¨
G1ï¼Garbage-Firstï¼å徿¶éå¨å¨ JDK 7 ä¸é¦æ¬¡å¼å
¥ï¼ä½ä¸ºä¸ç§è¯éªæ§çå徿¶éå¨ãå°äº JDK 8ï¼G1 å¾å°äºè¿ä¸æ¥çå®ååæ¹è¿ï¼åè½åºæ¬å·²ç»å®å
¨å®ç°ï¼æä¸ºä¸ä¸ªç¨³å®ãå¯ç¨äºç产ç¯å¢çå徿¶éå¨ã
G1 æ¶éå¨çè¿ä½å¤§è´å为以ä¸å 个æ¥éª¤ï¼
- **åå§æ è®°**ï¼ çæåé¡¿ï¼Stop-The-Worldï¼STWï¼ï¼æ è®°ä» GC Roots å¯ç´æ¥å¼ç¨ç对象ï¼å³æ è®°ææç´æ¥å¯è¾¾çæ´»è·å¯¹è±¡
- **å¹¶åæ è®°**ï¼ä¸åºç¨å¹¶åè¿è¡ï¼æ è®°ææå¯è¾¾å¯¹è±¡ã è¿ä¸é¶æ®µå¯è½æç»è¾é¿æ¶é´ï¼åå³äºå ç大å°åå¯¹è±¡çæ°éã
- **æç»æ è®°**ï¼ çæåé¡¿ï¼STWï¼ï¼å¤çå¹¶åæ è®°é¶æ®µç»æåæ®ççå°éæªå¤ççå¼ç¨åæ´ã
- **çéåæ¶**ï¼æ ¹æ®æ è®°ç»æï¼éæ©åæ¶ä»·å¼é«çåºåï¼å¤å¶åæ´»å¯¹è±¡å°æ°åºåï¼åæ¶æ§åºåå
åãè¿ä¸é¶æ®µå
å«ä¸ä¸ªæå¤ä¸ªåé¡¿ï¼STWï¼ï¼å
·ä½åå³äºåæ¶çå¤æåº¦ã

**G1 æ¶éå¨å¨åå°ç»´æ¤äºä¸ä¸ªä¼å
åè¡¨ï¼æ¯æ¬¡æ ¹æ®å
è®¸çæ¶éæ¶é´ï¼ä¼å
鿩忶价弿大ç Region(è¿ä¹å°±æ¯å®çåå Garbage-First çç±æ¥)** ãè¿ç§ä½¿ç¨ Region ååå
å空é´ä»¥åæä¼å
级çåºååæ¶æ¹å¼ï¼ä¿è¯äº G1 æ¶éå¨å¨æéæ¶é´å
å¯ä»¥å°½å¯è½é«çæ¶éæçï¼æå
ååæ´ä¸ºé¶ï¼ã
### âï¸ZGC æåªäºæ¹è¿ï¼
ä¸ CMSãParNew å G1 类似ï¼ZGC ä¹éç¨æ è®°-å¤å¶ç®æ³ï¼ä¸è¿ ZGC å¯¹è¯¥ç®æ³åäºé大æ¹è¿ã
ZGC å¯ä»¥å°æåæ¶é´æ§å¶å¨å 毫ç§ä»¥å
ï¼ä¸æåæ¶é´ä¸åå å
å大å°çå½±åï¼åºç° Stop The World çæ
åµä¼æ´å°ï¼ä½ä»£ä»·æ¯çºç²äºä¸äºååéãZGC æå¤§æ¯æ 16TB çå å
åã
ZGC å¨ Java11 ä¸å¼å
¥ï¼å¤äºè¯éªé¶æ®µãç»è¿å¤ä¸ªçæ¬çè¿ä»£ï¼ä¸æçå®ååä¿®å¤é®é¢ï¼ZGC å¨ Java15 å·²ç»å¯ä»¥æ£å¼ä½¿ç¨äºã
ä¸è¿ï¼é»è®¤çåå¾åæ¶å¨ä¾ç¶æ¯ G1ãä½ å¯ä»¥éè¿ä¸é¢çåæ°å¯ç¨ ZGCï¼
```bash
java -XX:+UseZGC className
```
å¨ Java21 ä¸ï¼å¼å
¥äºå代 ZGCï¼æåæ¶é´å¯ä»¥ç¼©çå° 1 毫ç§ä»¥å
ã
ä½ å¯ä»¥éè¿ä¸é¢çåæ°å¯ç¨å代 ZGCï¼
```bash
java -XX:+UseZGC -XX:+ZGenerational className
```
å
³äº ZGC æ¶éå¨ç详ç»ä»ç»æ¨èççè¿å ç¯æç« ï¼
- [ä»å代 GC ç®æ³è§åº¦åæ ZGC - äº¬ä¸ææ¯](https://mp.weixin.qq.com/s/ExkB40cq1_Z0ooDzXn7CVw)
- [æ°ä¸ä»£åå¾åæ¶å¨ ZGC çæ¢ç´¢ä¸å®è·µ - ç¾å¢ææ¯å¢é](https://tech.meituan.com/2020/08/06/new-zgc-practice-in-meituan.html)
- [æè´å
«è¡æä¹ JVM åå¾åæ¶å¨ G1&ZGC 详解 - é¿éäºå¼åè
](https://mp.weixin.qq.com/s/Ywj3XMws0IIK-kiUllN87Q)
## âï¸åäº²å§æ´¾æ¨¡å
### åäº²å§æ´¾æ¨¡åæçæ¯ï¼
ç±»å è½½å¨æå¾å¤ç§ï¼å½æä»¬æ³è¦å è½½ä¸ä¸ªç±»çæ¶åï¼å
·ä½æ¯åªä¸ªç±»å è½½å¨å è½½å¢ï¼è¿å°±éè¦æå°åäº²å§æ´¾æ¨¡åäºã
æ ¹æ®å®ç½ä»ç»ï¼
> The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.
ç¿»è¯è¿æ¥å¤§æ¦çæææ¯ï¼
> `ClassLoader` 类使ç¨å§ææ¨¡åæ¥æç´¢ç±»åèµæºãæ¯ä¸ª `ClassLoader` å®ä¾é½æä¸ä¸ªç¸å
³çç¶ç±»å è½½å¨ãéè¦æ¥æ¾ç±»æèµæºæ¶ï¼`ClassLoader` å®ä¾ä¼å¨è¯å¾äº²èªæ¥æ¾ç±»æèµæºä¹åï¼å°æç´¢ç±»æèµæºçä»»å¡å§æç»å
¶ç¶ç±»å è½½å¨ã
> èææºä¸è¢«ç§°ä¸º "bootstrap class loader"çå
置类å è½½å¨æ¬èº«æ²¡æç¶ç±»å è½½å¨ï¼ä½æ¯å¯ä»¥ä½ä¸º `ClassLoader` å®ä¾çç¶ç±»å è½½å¨ã
ä»ä¸é¢çä»ç»å¯ä»¥çåºï¼
- `ClassLoader` 类使ç¨å§ææ¨¡åæ¥æç´¢ç±»åèµæºã
- åäº²å§æ´¾æ¨¡åè¦æ±é¤äºé¡¶å±çå¯å¨ç±»å è½½å¨å¤ï¼å
¶ä½çç±»å è½½å¨é½åºæèªå·±çç¶ç±»å è½½å¨ã
- `ClassLoader` å®ä¾ä¼å¨è¯å¾äº²èªæ¥æ¾ç±»æèµæºä¹åï¼å°æç´¢ç±»æèµæºçä»»å¡å§æç»å
¶ç¶ç±»å è½½å¨ã
ä¸å¾å±ç¤ºçåç§ç±»å è½½å¨ä¹é´ç屿¬¡å
³ç³»è¢«ç§°ä¸ºç±»å è½½å¨çâ**åäº²å§æ´¾æ¨¡å(Parents Delegation Model)**âã

注æ â ï¸ï¼åäº²å§æ´¾æ¨¡å并䏿¯ä¸ç§å¼ºå¶æ§ç约æï¼åªæ¯ JDK 宿¹æ¨èçä¸ç§æ¹å¼ã妿æä»¬å 为æäºç¹æ®éæ±æ³è¦æç ´åäº²å§æ´¾æ¨¡åï¼ä¹æ¯å¯ä»¥çï¼åæä¼ä»ç»å
·ä½çæ¹æ³ã
å
¶å®è¿ä¸ªå亲翻è¯ç容æè®©å«äººè¯¯è§£ï¼æä»¬ä¸è¬çè§£çåäº²é½æ¯ç¶æ¯ï¼è¿éçå亲æ´å¤å°è¡¨è¾¾çæ¯âç¶æ¯è¿ä¸è¾âç人èå·²ï¼å¹¶ä¸æ¯è¯´ççæä¸ä¸ª `MotherClassLoader` åä¸ä¸ª`FatherClassLoader` ã个人è§å¾ç¿»è¯æåäº²å§æ´¾æ¨¡åæ´å¥½ä¸äºï¼ä¸è¿ï¼å½å
æ¢ç¶ç¿»è¯æäºåäº²å§æ´¾æ¨¡åå¹¶æµä¼ äºï¼æç
§è¿ä¸ªæ¥ä¹æ²¡é®é¢ï¼ä¸è¦è¢«è¯¯è§£äºå°±å¥½ã
å¦å¤ï¼ç±»å è½½å¨ä¹é´çç¶åå
³ç³»ä¸è¬ä¸æ¯ä»¥ç»§æ¿çå
³ç³»æ¥å®ç°çï¼èæ¯é常使ç¨ç»åå
³ç³»æ¥å¤ç¨ç¶å è½½å¨ç代ç ã
```java
public abstract class ClassLoader {
...
// ç»å
private final ClassLoader parent;
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
...
}
```
å¨é¢å对象ç¼ç¨ä¸ï¼æä¸æ¡é常ç»å
¸ç设计ååï¼**ç»åä¼äºç»§æ¿ï¼å¤ç¨ç»åå°ç¨ç»§æ¿ã**
### å¦ä½æç ´æç ´åäº²å§æ´¾æ¨¡åï¼
å®ä¹å è½½å¨çè¯ï¼éè¦ç»§æ¿ `ClassLoader` ã妿æä»¬ä¸æ³æç ´åäº²å§æ´¾æ¨¡åï¼å°±éå `ClassLoader` ç±»ä¸ç `findClass()` æ¹æ³å³å¯ï¼æ æ³è¢«ç¶ç±»å è½½å¨å è½½çç±»æç»ä¼éè¿è¿ä¸ªæ¹æ³è¢«å è½½ã使¯ï¼å¦ææ³æç ´åäº²å§æ´¾æ¨¡ååéè¦éå `loadClass()` æ¹æ³ã
为ä»ä¹æ¯éå `loadClass()` æ¹æ³æç ´åäº²å§æ´¾æ¨¡åå¢ï¼åäº²å§æ´¾æ¨¡åçæ§è¡æµç¨å·²ç»è§£éäºï¼
> ç±»å è½½å¨å¨è¿è¡ç±»å è½½çæ¶åï¼å®é¦å
ä¸ä¼èªå·±å»å°è¯å è½½è¿ä¸ªç±»ï¼èæ¯æè¿ä¸ªè¯·æ±å§æ´¾ç»ç¶ç±»å è½½å¨å»å®æï¼è°ç¨ç¶å è½½å¨ `loadClass()`æ¹æ³æ¥å 载类ï¼ã
éå `loadClass()`æ¹æ³ä¹åï¼æä»¬å°±å¯ä»¥æ¹åä¼ ç»åäº²å§æ´¾æ¨¡åçæ§è¡æµç¨ãä¾å¦ï¼åç±»å è½½å¨å¯ä»¥å¨å§æ´¾ç»ç¶ç±»å è½½å¨ä¹åï¼å
èªå·±å°è¯å è½½è¿ä¸ªç±»ï¼æè
å¨ç¶ç±»å è½½å¨è¿åä¹åï¼åå°è¯ä»å
¶ä»å°æ¹å è½½è¿ä¸ªç±»ãå
·ä½çè§åç±æä»¬èªå·±å®ç°ï¼æ ¹æ®é¡¹ç®éæ±å®å¶åã
æä»¬æ¯è¾çæç Tomcat æå¡å¨ä¸ºäºè½å¤ä¼å
å è½½ Web åºç¨ç®å½ä¸çç±»ï¼ç¶ååå è½½å
¶ä»ç®å½ä¸çç±»ï¼å°±èªå®ä¹äºç±»å è½½å¨ `WebAppClassLoader` æ¥æç ´åäº²å§ææºå¶ãè¿ä¹æ¯ Tomcat ä¸ Web åºç¨ä¹é´çç±»å®ç°é离çå
·ä½åçã
Tomcat çç±»å è½½å¨ç屿¬¡ç»æå¦ä¸ï¼

Tomcat è¿å个èªå®ä¹çç±»å è½½å¨å¯¹åºçç®å½å¦ä¸ï¼
- `CommonClassLoader`对åº`/common/*`
- `CatalinaClassLoader`对åº`/server/*`
- `SharedClassLoader`å¯¹åº `/shared/*`
- `WebAppClassloader`å¯¹åº `/webapps//WEB-INF/*`
ä»å¾ä¸çå§æ´¾å
³ç³»ä¸å¯ä»¥çåºï¼
- `CommonClassLoader`ä½ä¸º `CatalinaClassLoader` å `SharedClassLoader` çç¶å è½½å¨ã`CommonClassLoader` è½å è½½çç±»é½å¯ä»¥è¢« `CatalinaClassLoader` å `SharedClassLoader` 使ç¨ãå æ¤ï¼`CommonClassLoader` æ¯ä¸ºäºå®ç°å
Œ
±ç±»åºï¼å¯ä»¥è¢«ææ Web åºç¨å Tomcat å
é¨ç»ä»¶ä½¿ç¨çç±»åºï¼çå
±äº«åé离ã
- `CatalinaClassLoader` å `SharedClassLoader` è½å è½½çç±»åä¸å¯¹æ¹ç¸äºé离ã`CatalinaClassLoader` ç¨äºå è½½ Tomcat èªèº«çç±»ï¼ä¸ºäºé离 Tomcat æ¬èº«çç±»å Web åºç¨çç±»ã`SharedClassLoader` ä½ä¸º `WebAppClassLoader` çç¶å è½½å¨ï¼ä¸é¨æ¥å è½½ Web åºç¨ä¹é´å
±äº«çç±»æ¯å¦ SpringãMybatisã
- æ¯ä¸ª Web åºç¨é½ä¼å建ä¸ä¸ªåç¬ç `WebAppClassLoader`ï¼å¹¶å¨å¯å¨ Web åºç¨ç线ç¨é设置线ç¨çº¿ç¨ä¸ä¸æç±»å è½½å¨ä¸º `WebAppClassLoader`ãå个 `WebAppClassLoader` å®ä¾ä¹é´ç¸äºé离ï¼è¿èå®ç° Web åºç¨ä¹é´çç±»éã
å纯ä¾é èªå®ä¹ç±»å è½½å¨æ²¡åæ³æ»¡è¶³æäºåºæ¯çè¦æ±ï¼ä¾å¦ï¼æäºæ
åµä¸ï¼é«å±çç±»å è½½å¨éè¦å è½½ä½å±çå è½½å¨æè½å è½½çç±»ã
æ¯å¦ï¼SPI ä¸ï¼SPI çæ¥å£ï¼å¦ `java.sql.Driver`ï¼æ¯ç± Java æ ¸å¿åºæä¾çï¼ç±`BootstrapClassLoader` å è½½ãè SPI çå®ç°ï¼å¦`com.mysql.cj.jdbc.Driver`ï¼æ¯ç±ç¬¬ä¸æ¹ä¾åºåæä¾çï¼å®ä»¬æ¯ç±åºç¨ç¨åºç±»å è½½å¨æè
èªå®ä¹ç±»å è½½å¨æ¥å è½½çãé»è®¤æ
åµä¸ï¼ä¸ä¸ªç±»åå
¶ä¾èµç±»ç±åä¸ä¸ªç±»å è½½å¨å è½½ãæä»¥ï¼å è½½ SPI çæ¥å£çç±»å è½½å¨ï¼`BootstrapClassLoader`ï¼ä¹ä¼ç¨æ¥å è½½ SPI çå®ç°ãæç
§åäº²å§æ´¾æ¨¡åï¼`BootstrapClassLoader` æ¯æ æ³æ¾å° SPI çå®ç°ç±»çï¼å ä¸ºå®æ æ³å§æç»åç±»å è½½å¨å»å°è¯å è½½ã
忝å¦ï¼å设æä»¬ç项ç®ä¸æ Spring ç jar å
ï¼ç±äºå
¶æ¯ Web åºç¨ä¹é´å
±äº«çï¼å æ¤ä¼ç± `SharedClassLoader` å è½½ï¼Web æå¡å¨æ¯ Tomcatï¼ãæä»¬é¡¹ç®ä¸æä¸äºç¨å°äº Spring çä¸å¡ç±»ï¼æ¯å¦å®ç°äº Spring æä¾çæ¥å£ãç¨å°äº Spring æä¾ç注解ãæä»¥ï¼å è½½ Spring çç±»å è½½å¨ï¼ä¹å°±æ¯ `SharedClassLoader`ï¼ä¹ä¼ç¨æ¥å è½½è¿äºä¸å¡ç±»ã使¯ä¸å¡ç±»å¨ Web åºç¨ç®å½ä¸ï¼ä¸å¨ `SharedClassLoader` çå 载路å¾ä¸ï¼æä»¥ `SharedClassLoader` æ æ³æ¾å°ä¸å¡ç±»ï¼ä¹å°±æ æ³å è½½å®ä»¬ã
å¦ä½è§£å³è¿ä¸ªé®é¢å¢ï¼ è¿ä¸ªæ¶åå°±éè¦ç¨å° **线ç¨ä¸ä¸æç±»å è½½å¨ï¼`ThreadContextClassLoader`ï¼** äºã
æ¿ Spring è¿ä¸ªä¾åæ¥è¯´ï¼å½ Spring éè¦å è½½ä¸å¡ç±»çæ¶åï¼å®ä¸æ¯ç¨èªå·±çç±»å è½½å¨ï¼èæ¯ç¨å½å线ç¨çä¸ä¸æç±»å è½½å¨ãè¿è®°å¾æä¸é¢è¯´çåï¼æ¯ä¸ª Web åºç¨é½ä¼å建ä¸ä¸ªåç¬ç `WebAppClassLoader`ï¼å¹¶å¨å¯å¨ Web åºç¨ç线ç¨é设置线ç¨çº¿ç¨ä¸ä¸æç±»å è½½å¨ä¸º `WebAppClassLoader`ãè¿æ ·å°±å¯ä»¥è®©é«å±çç±»å è½½å¨ï¼`SharedClassLoader`ï¼åå©åç±»å è½½å¨ï¼ `WebAppClassLoader`ï¼æ¥å è½½ä¸å¡ç±»ï¼ç ´åäº Java çç±»å è½½å§ææºå¶ï¼è®©åºç¨éå使ç¨ç±»å è½½å¨ã
线ç¨ä¸ä¸æç±»å è½½å¨çåçæ¯å°ä¸ä¸ªç±»å è½½å¨ä¿åå¨çº¿ç¨ç§ææ°æ®éï¼è·çº¿ç¨ç»å®ï¼ç¶åå¨éè¦çæ¶åååºæ¥ä½¿ç¨ãè¿ä¸ªç±»å è½½å¨é常æ¯ç±åºç¨ç¨åºæè
容å¨ï¼å¦ Tomcatï¼è®¾ç½®çã
`Java.lang.Thread` ä¸ç`getContextClassLoader()`å `setContextClassLoader(ClassLoader cl)`åå«ç¨æ¥è·åå设置线ç¨çä¸ä¸æç±»å è½½å¨ãå¦ææ²¡æéè¿`setContextClassLoader(ClassLoader cl)`è¿è¡è®¾ç½®çè¯ï¼çº¿ç¨å°ç»§æ¿å
¶ç¶çº¿ç¨çä¸ä¸æç±»å è½½å¨ã
Spring è·å线ç¨çº¿ç¨ä¸ä¸æç±»å è½½å¨ç代ç å¦ä¸ï¼
```java
cl = Thread.currentThread().getContextClassLoader();
```
æå
´è¶£çå°ä¼ä¼´å¯ä»¥èªè¡æ·±å
¥ç ç©¶ä¸ä¸ Tomcat æç ´åäº²å§æ´¾æ¨¡åçåçï¼æ¨èèµæï¼[ãæ·±å
¥æè§£ Tomcat & Jettyã](http://gk.link/a/10Egr)ã
## âï¸é®é¢ææ¥
### ä½ ç¥éåªäº Java æ§è½ä¼ååé®é¢ææ¥å·¥å
·ï¼
JDK èªå¸¦çå¯è§ååæå·¥å
·ï¼
- **JConsole** ï¼åºäº JMX çå¯è§åçè§ã管çå·¥å
·ï¼å¯ä»¥ç¨äºæ¥çåºç¨ç¨åºçè¿è¡æ¦åµãå
åã线ç¨ãç±»ãVM æ¦æ¬ãMBean çä¿¡æ¯ã
- **VisualVM**ï¼åºäº NetBeans å¹³å°å¼åï¼å
·å¤äºæä»¶æ©å±åè½çç¹æ§ãå©ç¨å®ä¸ä»
è½å¤çæ§æå¡ç CPUãå
åã线ç¨ãç±»çä¿¡æ¯ï¼è¿å¯ä»¥æè·æå
³ JVM 软件å®ä¾çæ°æ®ï¼å¹¶å°è¯¥æ°æ®ä¿åå°æ¬å°ç³»ç»ï¼ä»¥ä¾åææ¥çæä¸å
¶ä»ç¨æ·å
±äº«ãæ ¹æ®ãæ·±å
¥çè§£ Java èææºãä»ç»ï¼âVisualVM çæ§è½åæåè½çè³æ¯èµ· JProfilerãYourKit çä¸ä¸ä¸æ¶è´¹ç Profiling å·¥å
·é½ä¸ä¼éè²å¤å°ï¼èä¸ VisualVM è¿æä¸ä¸ªå¾å¤§çä¼ç¹ï¼ä¸éè¦è¢«çè§çç¨åºåºäºç¹æ® Agent è¿è¡ï¼å æ¤ä»å¯¹åºç¨ç¨åºçå®é
æ§è½çå½±åå¾å°ï¼ä½¿å¾ä»å¯ä»¥ç´æ¥åºç¨å¨ç产ç¯å¢ä¸ãè¿ä¸ªä¼ç¹æ¯ JProfilerãYourKit çå·¥å
·æ æ³ä¸ä¹åª²ç¾çâã
JDK èªå¸¦çå½ä»¤è¡å·¥å
·ï¼
- **`jps`** (JVM Process Statusï¼: 类似 UNIX ç `ps` å½ä»¤ãç¨äºæ¥çææ Java è¿ç¨çå¯å¨ç±»ãä¼ å
¥åæ°å Java èææºåæ°çä¿¡æ¯ï¼
- **`jstat`**ï¼JVM Statistics Monitoring Toolï¼: ç¨äºæ¶é HotSpot èææºåæ¹é¢çè¿è¡æ°æ®;
- **`jinfo`** (Configuration Info for Java) : Configuration Info for Java,æ¾ç¤ºèææºé
置信æ¯;
- **`jmap`** (Memory Map for Java) : çæå 转å¨å¿«ç
§;
- **`jhat`** (JVM Heap Dump Browser) : ç¨äºåæ heapdump æä»¶ï¼å®ä¼å»ºç«ä¸ä¸ª HTTP/HTML æå¡å¨ï¼è®©ç¨æ·å¯ä»¥å¨æµè§å¨ä¸æ¥çåæç»æãJDK9 ç§»é¤äº jhatï¼
- **`jstack`** (Stack Trace for Java) : çæèææºå½åæ¶å»ç线ç¨å¿«ç
§ï¼çº¿ç¨å¿«ç
§å°±æ¯å½åèææºå
æ¯ä¸æ¡çº¿ç¨æ£å¨æ§è¡çæ¹æ³å æ çéåã
ç¬¬ä¸æ¹å·¥å
·ï¼
- **MAT**ï¼ä¸æ¬¾åè½å¼ºå¤§ç Java å å
ååæå¨ï¼å¯ä»¥ç¨äºæ¥æ¾å
åæ³æ¼ä»¥åæ¥çå
åæ¶èæ
åµï¼ç¨æ·å¯ä»¥å©ç¨ VisualVM æè
æ¯ `jmap` å½ä»¤çäº§å æä»¶ï¼ç¶å导å
¥å·¥å
·ä¸è¿è¡åæã
- **GCeasy**ï¼ä¸æ¬¾å¨çº¿ç GC æ¥å¿åæå¨ï¼ä½¿ç¨èµ·æ¥é常æ¹ä¾¿ï¼ç¨æ·å¯ä»¥éè¿å®ç Web ç½ç«å¯¼å
¥ GC æ¥å¿ï¼å®æ¶è¿è¡å
åæ³æ¼æ£æµãGC æååå åæãJVM é
置建议ä¼åçåè½ãç½ç«å°åï¼ ã
- **GCViewer**ï¼ä¸æ¬¾é常强大ç GC æ¥å¿å¯è§ååæå·¥å
·ï¼åè½å¼ºå¤§èä¸å®å
¨å
è´¹ã
- **JProfiler**ï¼ä¸æ¬¾åç¨çæ§è½åæå©å¨ï¼åè½å¼ºå¤§ï¼ä½éè¦ä»è´¹ä½¿ç¨ã 宿便´æ·±å
¥çæ§è½åæåè½ï¼ä¾å¦æ¹æ³è°ç¨åæãå
ååé
åæçã
- **Arthas**ï¼é¿é弿ºç䏿¬¾çº¿ä¸çæ§è¯æå·¥å
·ï¼å¯ä»¥æ¥çåºç¨è´è½½ãå
åãgcã线ç¨çä¿¡æ¯ã
### å¦ä½æ¥çæå¡å¨ä¸è¿è¡ç Java è¿ç¨ï¼
JDK èªå¸¦ç `jps` (JVM Process Status) å½ä»¤ä¸é¨ç¨äºååºå½åç¨æ·ä¸æææ£å¨è¿è¡ç JVM å®ä¾ã
`jps` çåºç¡ç¨æ³åå ä¸ªæ ¸å¿åæ°å¦ä¸ï¼
- **`jps`**ï¼è¿æ¯æåºç¡çç¨æ³ï¼å®ä¼ååº Java è¿ç¨ç **LVMID**ï¼æ¬å°èææºå¯ä¸ IDï¼éå¸¸å°±æ¯æä½ç³»ç»çè¿ç¨å· PIDï¼å**主类å**ï¼æ Jar å
åï¼ã
- **`jps -l`**ï¼è¿æ¯ææå¸¸ç¨çåæ°ä¹ä¸ãå®ä¼è¾åºä¸»ç±»ç**宿´å
å**ï¼æè
妿åºç¨æ¯éè¿ Jar å
è¿è¡çï¼ä¼è¾åº Jar å
ç**宿´è·¯å¾**ãè¿å¨åä¸å°æºå¨ä¸é¨ç½²äºå¤ä¸ªæ¥èªä¸å项ç®ç Java åºç¨æ¶ï¼è½é常æ¸
æ°å°åºåå®ä»¬ã
- **`jps -v`**ï¼è¿ä¸ªåæ°ä¹é常å®ç¨ï¼å°¤å
¶æ¯å¨ææ¥é
ç½®é®é¢æ¶ãå®ä¼æ¾ç¤ºä¼ éç» JVM çåæ°ï¼ä¾å¦ `-Xmx`ã`-Xms`ã`-XX:+UseG1GC` çãéè¿å®ï¼æå¯ä»¥å¿«é确认åºç¨çå
åé
ç½®ãGC çç¥çæ¯å¦ç¬¦å颿ã
- **`jps -m`**ï¼è¿ä¸ªåæ°ç¨äºæ¥çä¼ éç»ä¸»å½æ° `main()` çåæ°ã彿们éè¦ç¡®è®¤ç¨åºå¯å¨æ¶ä¼ å
¥çä¸å¡åæ°æ¯å¦æ£ç¡®æ¶ï¼å®é常æç¨ã
å¨æäºæ
åµä¸ï¼`jps` å½ä»¤å¯è½æ æ³æ»¡è¶³éæ±ï¼è¿æ¶æä¼éç¨æ åçæä½ç³»ç»å½ä»¤ï¼
1. **æéé®é¢**ï¼jps é»è®¤åªè½çå°ç±**å½åç¨æ·**å¯å¨ç Java è¿ç¨ã妿éè¦æ¥çæå¡å¨ä¸ææç¨æ·ï¼å¦ root æå
¶ä»ä¸å¡ç¨æ·ï¼ç Java è¿ç¨ï¼jps å°±ä¼åéã
2. **ç¯å¢é®é¢**ï¼å¨ä¸äºæç®çç产ç¯å¢æ Docker 容å¨ä¸ï¼å¯è½åªå®è£
äº JRE èæ²¡æå®æ´ç JDKï¼æ¤æ¶ jps å½ä»¤å¯è½ä¸åå¨ã
å¨è¿äºæ
åµä¸ï¼æä¼ä½¿ç¨ ps å½ä»¤æ¥æ¥æ¾ï¼ä¾å¦ï¼
```bash
# ååºææè¿ç¨ï¼ç¶åéè¿ grep è¿æ»¤åºå
å« "java" å
³é®åçè¿ç¨
ps -ef | grep java
```
### å å
åç¸å
³ç JVM åæ°æåªäºï¼
**å å
å大尿§å¶**ï¼
1. **`-Xms`** ï¼è®¾ç½® JVM åå§å å
å大å°ï¼å¦`-Xms512m`表示åå§å 为 512MBï¼ã
2. **`-Xmx`** ï¼è®¾ç½® JVM æå¤§å å
å大å°ï¼å¦`-Xmx1g`表示æå¤§å 为 1GBï¼ã
å¨ç产ç¯å¢ä¸ï¼å¼ºçå»ºè®®å° `-Xms` å `-Xmx` 设置为ç¸åçå¼ãè¿æ ·åå¯ä»¥é¿å
JVM å¨è¿è¡æ¶æ ¹æ®è´è½½æ
åµå¨æå°æ¶ç¼©åæ©å±å å
åï¼è¿ä¸ªè¿ç¨ä¼å¼åä¸å¿
è¦ç Full GC åæ§è½æå¨ï¼ä»èæé«æå¡çç¨³å®æ§åååºé度ã
**æ°ç代ä¸è年代**ï¼
1. **`-Xmn`**ï¼è¿æ¯æç´æ¥æ§å¶æ°ç代大å°çæ¹å¼ï¼ä¼å
级é«äº -`XX:NewRatio`ã设置åï¼è年代ç大å°å°±æ¯ `-Xmx` åå» `-Xmn`ã彿们坹åºç¨ç对象çå½å¨æææç¡®ç夿æ¶ï¼ä¾å¦ï¼æå¤§éçççå½å¨æå¯¹è±¡ï¼ï¼å¯ä»¥ç´æ¥ç»æ°ç代ä¸ä¸ªåéç大å°ï¼ä»¥è¾¾å°æ´å¥½ç GC æ§è½ã
2. **`-XX:NewRatio`**ï¼è¿æ¯å¦ä¸ç§è°èæ°ç代大å°çæ¹å¼ï¼é»è®¤å¼ä¸º 2ï¼è¡¨ç¤ºè年代:æ°ç代 = 2:1ãå æ¤ï¼æ°ç代é»è®¤å æ´ä¸ªå ç 1/3ãå¦æè®¾ç½®ä¸º 3ï¼åæ°ç代å å ç 1/4ãéå¸¸å¨ `-Xmn` å `-XX:NewRatio`ä¸éæ©ä¸ä¸ªä½¿ç¨å³å¯ã
3. **`-XX:SurvivorRatio`**ï¼è®¾ç½®æ°çä»£ä¸ Eden åºä¸å个 Survivor åºçæ¯ä¾ãé»è®¤å¼ä¸º 8ï¼è¡¨ç¤º Eden : From Survivor : To Survivor = 8:1:1ãæä»¥ Eden åºå æ´ä¸ªæ°ç代ç 8/10ãè¿ä¸ªæ¯ä¾ä¼å½±å对象è½å¦å¨æ°ç代ä¸âåæ´»âè¶³å¤é¿çæ¶é´ã妿 Survivor åºå¤ªå°ï¼å³ `-XX:SurvivorRatio` å¼è¿å¤§ï¼ï¼Minor GC ååæ´»ç对象å¯è½å 为æ¾ä¸ä¸è被迫æåè¿å
¥è年代ï¼å¢å Full GC çååã
**å å
åæº¢åºç¸å
³åæ°**ï¼
1. **`-XX:+HeapDumpOnOutOfMemoryError`** ï¼å½åç`OutOfMemoryError`ï¼OOMï¼æ¶ï¼èªå¨çæå è½¬å¨æä»¶ï¼`.hprof`ï¼ï¼è®°å½å å
åå¯¹è±¡ç¶æã
2. **`-XX:HeapDumpPath`** ï¼æå® OOM æ¶å è½¬å¨æä»¶çä¿åè·¯å¾ï¼å¦`-XX:HeapDumpPath=/logs/heapdump.hprof`ï¼ï¼é»è®¤çæå¨ç¨åºè¿è¡ç®å½ã
æéè¦ç JVM åæ°å¯ä»¥åèè¿ç¯æç« ï¼[æéè¦ç JVM åæ°æ»ç»](https://javaguide.cn/java/jvm/jvm-parameters-intro.html)ã
### å¦ä½æ£æµæ»éï¼
- 使ç¨`jmap`ã`jstack`çå½ä»¤æ¥ç JVM çº¿ç¨æ åå å
åçæ
åµãå¦æææ»éï¼`jstack` çè¾åºä¸é叏伿 `Found one Java-level deadlock:`çåæ ·ï¼åé¢ä¼è·çæ»éç¸å
³ç线ç¨ä¿¡æ¯ãå¦å¤ï¼å®é
项ç®ä¸è¿å¯ä»¥æé
使ç¨`top`ã`df`ã`free`çå½ä»¤æ¥çæä½ç³»ç»çåºæ¬æ
åµï¼åºç°æ»éå¯è½ä¼å¯¼è´ CPUãå
åçèµæºæ¶èè¿é«ã
- éç¨ VisualVMãJConsole çå·¥å
·è¿è¡ææ¥ã
è¿é以 JConsole å·¥å
·ä¸ºä¾è¿è¡æ¼ç¤ºã
é¦å
ï¼æä»¬è¦æ¾å° JDK ç bin ç®å½ï¼æ¾å° jconsole å¹¶å廿å¼ã

å¯¹äº MAC ç¨æ·æ¥è¯´ï¼å¯ä»¥éè¿ `/usr/libexec/java_home -V`æ¥ç JDK å®è£
ç®å½ï¼æ¾å°åéè¿ `open . + æä»¶å¤¹å°å`æå¼å³å¯ãä¾å¦ï¼ææ¬å°çæä¸ª JDK çè·¯å¾æ¯ï¼
```bash
open . /Users/guide/Library/Java/JavaVirtualMachines/corretto-1.8.0_252/Contents/Home
```
æå¼ jconsole åï¼è¿æ¥å¯¹åºçç¨åºï¼ç¶åè¿å
¥çº¿ç¨çé¢éæ©æ£æµæ»éå³å¯ï¼


详ç»ä»ç»å¯ä»¥æ¥çè¿ç¯æç« çæ»éé¨åå
容ï¼[Java å¹¶å常è§é¢è¯é¢æ»ç»ï¼ä¸ï¼](https://javaguide.cn/java/concurrent/java-concurrent-questions-01.html)ã
### ä»ä¹æ¯ Heap Dump æä»¶ï¼å¦ä½çæ Heap Dump æä»¶ï¼
Heap Dumpï¼å è½¬å¨æä»¶ï¼æ¯ Java èææºï¼JVMï¼å¨æä¸ªç¹å®æ¶é´ç¹ï¼å¯¹æ´ä¸ª Java **å å
å**çå¿«ç
§ã宿¯ä¸ä¸ªäºè¿å¶æä»¶ï¼å
å«äºå¿«ç
§æ¶å»å 䏿æå¯¹è±¡çä¿¡æ¯ï¼ä¾å¦ï¼
- **对象å®ä¾**ï¼æ¯ä¸ªå¯¹è±¡çæ°æ®ã
- **类信æ¯**ï¼å¯¹è±¡çç±»åãç¶ç±»ãéæå段çã
- **å¼ç¨å
³ç³»**ï¼å¯¹è±¡ä¹é´å¤æçå¼ç¨é¾ï¼å³è°ææäºè°ã
- **线ç¨ä¿¡æ¯**ï¼å æ ä¿¡æ¯ï¼ç¹å«æ¯ä¸ GC Roots ç¸å
³ççº¿ç¨æ ã
ç®åæ¥è¯´ï¼Heap Dump å°±æ¯ Java è¿ç¨å¨æä¸å»çâå
å X å
çâï¼æ¯è¯æå
åé®é¢çææ ¸å¿ãææå¨ç便®ã
#### èªå¨çæ
å¨ JVM å¯å¨åæ°ä¸å å
¥ä»¥ä¸é
ç½®ï¼è¿æ¯ç产ç¯å¢ææ¥ OOM é®é¢çé¦éæ¹æ¡ã
```bash
# å½åç OutOfMemoryError æ¶ï¼èªå¨çæ Heap Dump æä»¶
-XX:+HeapDumpOnOutOfMemoryError
# æå® Heap Dump æä»¶ççæè·¯å¾ï¼ä¾å¦ï¼/home/app/dumps/
-XX:HeapDumpPath=
```
#### æå¨çæ
å½åºç¨åºç°å
åçä¼¼å¼å¸¸ï¼å¦å
åæç»åé«ãGC é¢ç¹ï¼ä½æªå´©æºæ¶ï¼å¯ä»¥æå¨çæå¿«ç
§è¿è¡åæã
1. **jmap** ï¼JDK èªå¸¦çå½ä»¤è¡å·¥å
·ï¼ä¸é¨ç¨äºçæå å¿«ç
§ã使ç¨ç¤ºä¾ï¼`jmap -dump:format=b,file=heapdump.hprof `ã卿§è¡æ¶ä¼è§¦å STW ï¼å¯¼è´ Java è¿ç¨çæåé¡¿ï¼å¯¹ç产ç¯å¢æä¸å®å½±åãå¨é«çæ¬ JDK ä¸å·²ä¸æ¨èç´æ¥ä½¿ç¨ã
2. **jcmd** ï¼JDK 7 ä¹åå¼å
¥çå¤åè½å½ä»¤è¡å·¥å
·ï¼åè½æ¯ jmap æ´å¼ºå¤§ä¸äºï¼å¯ç¨æ¥æ¿ä»£ jmapï¼ä¾µå
¥æ§æ´å°ã使ç¨ç¤ºä¾ï¼`jcmd GC.heap_dump /path/to/heapdump.hprof`ã
3. **Arthas**ï¼é¿é巴巴弿ºç Java è¯æç¥å¨ï¼å¯¹åºç¨æ ä¾µå
¥ï¼åè½å¼ºå¤§ï¼å¯å¨ä¸é坿å¡çæ
åµä¸å¨æåæã使ç¨ç¤ºä¾ï¼`heapdump /tmp/heapdump.hprof`ã
4. **å¯è§åå·¥å
·**ï¼å¦ JVisualVMãJProfilerãYourKit çï¼é½æä¾äºå¾å½¢åçé¢ï¼ç¹å»æé®å³å¯çæ Heap Dump æä»¶ï¼å¹¶è½ç´æ¥è¿è¡åæï¼é常æ¹ä¾¿ã
### éå° OutOfMemoryError æä¹ææ¥è§£å³ï¼
æä»¬å¯ä»¥éè¿ MATãJVisualVM çå·¥å
·åæ Heap Dump æ¾å°å¯¼è´`OutOfMemoryError` çåå ã
以 MAT 为ä¾ï¼å
¶æä¾çæ³æ¼å«çï¼Leak Suspectsï¼æ¥åæ¯ MAT æå¼ºå¤§çåè½ä¹ä¸ãå®ä¼åºäºå¯åå¼ç®æ³èªå¨åææ´ä¸ªå ï¼ç´æ¥æåºæå¯ççå
åæ³æ¼ç¹ï¼å¹¶ç»åºè¯¦ç»çæ¥åï¼å
æ¬é®é¢ç»ä»¶ã累积ç¹ï¼Accumulation Pointï¼åå¼ç¨é¾çå¾ç¤ºã
å¦æâæ³æ¼å«çâæ¥åä¸å¤æç¡®ï¼æè
æ³è¦åæçæ¯å
åå ç¨è¿é«ï¼èéæ³æ¼ï¼é®é¢ï¼å¯ä»¥åæ¢å°**æ¯é
æ ï¼Dominator Treeï¼**è§å¾ãè¿ä¸ªè§å¾å°å
å对象å
³ç³»ç»ç»æä¸æ£µæ ï¼ç¶èç¹âæ¯é
âåèç¹ï¼å³ç¶èç¹è¢«åæ¶ï¼åèç¹ä¹å¿
è¢«åæ¶ï¼ã
ä¸é¢æ¯ä¸æ®µæ¨¡æåºç° `OutOfMemoryError`ç代ç ï¼
```java
import java.util.ArrayList;
import java.util.List;
public class SimpleLeak {
// éæéåï¼çå½å¨æä¸åºç¨ç¨åºä¸æ ·é¿
public static List staticList = new ArrayList<>();
public void leakMethod() {
// æ¯æ¬¡è°ç¨é½åéæéå䏿·»å ä¸ä¸ª 1MB çåèæ°ç»
staticList.add(new byte[1024 * 1024]); // 1MB
}
public static void main(String[] args) throws InterruptedException {
SimpleLeak leak = new SimpleLeak();
System.out.println("Starting leak simulation...");
// å¾ªç¯æ·»å å¯¹è±¡ï¼æ¨¡æå
åæ³æ¼è¿ç¨
for (int i = 0; i < 200; i++) {
leak.leakMethod();
System.out.println("Added " + (i + 1) + " MB to the list.");
Thread.sleep(200); // ç¨å¾®å»¶æ¶ï¼æ¹ä¾¿è§å¯
}
System.out.println("Leak simulation finished. Keeping process alive for Heap Dump.");
// ä¿æè¿ç¨åæ´»ï¼ä»¥ä¾¿æä»¬ææ¶é´çæ Heap Dump
Thread.sleep(Long.MAX_VALUE);
}
}
```
ä¸ºäºæ´å¿«è®©ç¨åºåºç° `OutOfMemoryError` é®é¢ï¼æä»¬å¯ä»¥æ
æè®¾ç½®ä¸ä¸ªè¾å°çå `-Xmx256m`ã
IDEA 设置 VM åæ°çæ¹å¼å¦ä¸å¾æç¤ºï¼

å
·ä½è®¾ç½®ç VM åæ°æ¯ï¼`-Xmx128m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=simple_leak.hprof`ï¼å
¶ä¸ï¼
- `-Xmx128m`ï¼è®¾ç½® JVM æå¤§å å
å为 128MBã
- `-XX:+HeapDumpOnOutOfMemoryError`ï¼å½ JVM åç `OutOfMemoryError` æ¶ï¼èªå¨çæå è½¬å¨æä»¶ï¼`.hprof`ï¼ã
- `-XX:HeapDumpPath=simple_leak.hprof`ï¼æå® OOM æ¶çæçå è½¬å¨æä»¶è·¯å¾åæä»¶åï¼è¿éæ¯ `simple_leak.hprof`ï¼ã
è¿è¡ç¨åºä¹åï¼ä¼åºç° `OutOfMemoryError`å¹¶èªå¨çæäº Heap Dump æä»¶ã
```bash
Starting leak simulation...
Added 1 MB to the list.
Added 2 MB to the list.
Added 3 MB to the list.
......
Added 113 MB to the list.
Added 114 MB to the list.
Added 115 MB to the list.
java.lang.OutOfMemoryError: Java heap space
Dumping heap to simple_leak.hprof ...
Heap dump file created [124217346 bytes in 0.121 secs]
```
æä»¬å° `.hprof` æä»¶å¯¼å
¥ MAT åï¼å®ä¼é¦å
è¿è¡è§£æåç´¢å¼ã宿åï¼å¯ä»¥æ¥çå®ç **âæ³æ¼å«çæ¥åâ (Leak Suspects Report)**ã

ä¸å¾ä¸ç Problem Suspect 1 å°±æ¯å¯è½åºç°å
åæ³é²çé®é¢åæï¼

- `cn.javaguide.SimpleLeak` ç±»ç± `sun.misc.Launcher$AppClassLoader` å è½½ï¼å ç¨ **120,589,040 åèï¼çº¦ 115MBï¼å å 98.80%ï¼**ï¼æ¯å
åå ç¨çæ ¸å¿ã
- å
å主è¦è¢« **`java.lang.Object[]` æ°ç»** å ç¨ï¼120,588,752 åèï¼ï¼è¯´æ `SimpleLeak` ä¸å¯è½åå¨å¤§é `Object` æ°ç»æªéæ¾ï¼è§¦åå
åæ³æ¼ã
Problem Suspect 1 çå¯ä»¥çå°æä¸ä¸ª **Details**ï¼ç¹è¿å»å³å¯çå°å
åæ³æ¼çå
³é®è·¯å¾åå¯¹è±¡å æ¯ï¼

å¯ä»¥çå°ï¼`SimpleLeak` ä¸ç**éæéå `staticList`** æ¯å
åæ³æ¼ç âæ ¹æºâï¼å 为éæåéçå½å¨æä¸ç±»ä¸è´ï¼è¥æç»åå
¶ä¸æ·»å 对象ä¸ä¸æ¸
çï¼ä¼å¯¼è´å¯¹è±¡æ æ³è¢« GC åæ¶ã
### éå°è¿ GC é®é¢åï¼æä¹åæåè§£å³çï¼
ç¾å¢ææ¯å¢éç [Java ä¸ 9 ç§å¸¸è§ç CMS GC é®é¢åæä¸è§£å³](https://tech.meituan.com/2020/11/12/java-9-cms-gc.html)è¿ç¯æç« å
± 2w+ åï¼è¯¦ç»ä»ç»äº GC åºç¡ï¼æ»ç»äº CMS GC çä¸äºå¸¸è§é®é¢åæä¸è§£å³åæ³ã