Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit01f5b73

Browse files
committed
Jvm总结
1 parentcaddfe0 commit01f5b73

File tree

6 files changed

+105
-2
lines changed

6 files changed

+105
-2
lines changed

‎README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@
6868
-[垃圾回收器](https://github.com/msJavaCoder/msJava/blob/master/docs/jvm/垃圾回收器.md)
6969
-[垃圾回收算法](https://github.com/msJavaCoder/msJava/blob/master/docs/jvm/垃圾回收算法.md)
7070
-[JVM确认可回收对象的方式](https://github.com/msJavaCoder/msJava/blob/master/docs/jvm/JVM确认可回收对象的方式.md)
71-
-[Java内存模型](https://github.com/msJavaCoder/msJava/blob/master/docs/jvm/Java内存模型.md)
71+
-[JMM内存可见性](https://github.com/msJavaCoder/msJava/blob/master/docs/jvm/JMM内存可见性.md)
72+
-[JMM保证](https://github.com/msJavaCoder/msJava/blob/master/docs/jvm/JMM保证.md)
73+
7274

7375
---
7476

‎_sidebar.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
*[垃圾回收器](./docs/jvm/垃圾回收器.md)
4646
*[垃圾回收算法](./docs/jvm/垃圾回收算法.md)
4747
*[类加载机制](./docs/jvm/类加载机制.md)
48-
*[Java内存模型](./docs/jvm/Java内存模型.md)
48+
*[JMM内存可见性](./docs/jvm/JMM内存可见性.md)
49+
*[JMM保证](./docs/jvm/JMM保证.md)
4950
*[Java运行时内存划分](./docs/jvm/Java运行时内存划分.md)
5051
*[JVM确认可回收对象的方式](./docs/jvm/JVM确认可回收对象的方式.md)
5152

‎docs/jvm/Java内存模型.md

Whitespace-only changes.

‎docs/jvm/Java运行时内存划分.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
>JVM内存区域分为线程私有区域(程序计数器、虚拟机栈、本地方法区),线程共享区域(堆内存、方法区)和直接内存。
44
5+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/BB/CgoB5l14lumAchYcAAB51w2Hj9Y736.png"alt="img"style="zoom:80%;" />
6+
57
+ 程序计数器
68

79
程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指令,每个运行中的线程都有一个独立的程序计数器,在方法正在执行时,该方法的程序计数器记录的是实时虚拟机字节码指令的地址;如果该方法执行的是Native方法,则程序计数器的值为空。

‎docs/jvm/垃圾回收算法.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,92 @@
2222
- 根据对象的生存周期,将堆分为新生代和老年代,然后根据各个年代的特点采用最适当的收集算法。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用**复制**算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用**标记 - 整理** 或者**标记 - 清除**
2323
- 严格地说,这并非是一种算法,而是一种思想,或者说是一种复合算法。
2424

25+
Java 的堆内存被分代管理,为什么要分代管理呢?分代管理主要是为了方便垃圾回收,这样做基于2个事实,第一,大部分对象很快就不再使用;第二,还有一部分不会立即无用,但也不会持续很长时间。
26+
27+
虚拟机划分为年轻代、老年代、和永久代,如下图所示。
28+
29+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/BB/CgoB5l14luqAFGZHAABEqvU94zM441.png"alt="img"style="zoom:50%;" />
30+
31+
- 年轻代主要用来存放新创建的对象,年轻代分为 Eden 区和两个 Survivor 区。大部分对象在 Eden 区中生成。当 Eden 区满时,还存活的对象会在两个 Survivor 区交替保存,达到一定次数的对象会晋升到老年代。
32+
33+
- 老年代用来存放从年轻代晋升而来的,存活时间较长的对象。
34+
35+
- 永久代,主要保存类信息等内容,这里的永久代是指对象划分方式,不是专指 1.7 的 PermGen,或者 1.8 之后的 Metaspace。
36+
37+
38+
根据年轻代与老年代的特点,JVM 提供了不同的垃圾回收算法。垃圾回收算法按类型可以分为引用计数法、复制法和标记清除法。
39+
40+
- 引用计数法是通过对象被引用的次数来确定对象是否被使用,缺点是无法解决循环引用的问题。
41+
42+
- 复制算法需要 from 和 to 两块相同大小的内存空间,对象分配时只在 from 块中进行,回收时把存活对象复制到 to 块中,并清空 from 块,然后交换两块的分工,即把 from 块作为 to 块,把 to 块作为 from 块。缺点是内存使用率较低。
43+
44+
- 标记清除算法分为标记对象和清除不在使用的对象两个阶段,标记清除算法的缺点是会产生内存碎片。
45+
46+
47+
JVM 中提供的年轻代回收算法 Serial、ParNew、Parallel Scavenge 都是复制算法,而 CMS、G1、ZGC 都属于标记清除算法。
48+
49+
##CMS 算法
50+
51+
基于分代回收理论,详细介绍几个典型的垃圾回收算法,先来看 CMS 回收算法。CMS 在 JDK1.7 之前可以说是最主流的垃圾回收算法。CMS 使用标记清除算法,优点是并发收集,停顿小。
52+
53+
CMS 算法如下图所示。
54+
55+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/DB/CgotOV14luqAB61oAABezTrv-gg961.png"alt="img"style="zoom:50%;" />
56+
57+
1. 第一个阶段是初始标记,这个阶段会 stop the world,标记的对象只是从 root 集最直接可达的对象;
58+
59+
2. 第二个阶段是并发标记,这时 GC 线程和应用线程并发执行。主要是标记可达的对象;
60+
61+
3. 第三个阶段是重新标记阶段,这个阶段是第二个 stop the world 的阶段,停顿时间比并发标记要小很多,但比初始标记稍长,主要对对象进行重新扫描并标记;
62+
63+
4. 第四个阶段是并发清理阶段,进行并发的垃圾清理;
64+
65+
5. 最后一个阶段是并发重置阶段,为下一次 GC 重置相关数据结构。
66+
67+
##G1 算法
68+
69+
G1 在 1.9 版本后成为 JVM 的默认垃圾回收算法,G1 的特点是保持高回收率的同时,减少停顿。
70+
71+
G1 算法取消了堆中年轻代与老年代的物理划分,但它仍然属于分代收集器。G1 算法将堆划分为若干个区域,称作 Region,如下图中的小方格所示。一部分区域用作年轻代,一部分用作老年代,另外还有一种专门用来存储巨型对象的分区。
72+
73+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/BB/CgoB5l14luqAR5suAAB5tOFWo20859.png"alt="img"style="zoom:50%;" />
74+
75+
G1 也和 CMS 一样会遍历全部的对象,然后标记对象引用情况,在清除对象后会对区域进行复制移动整合碎片空间。
76+
77+
78+
79+
G1 回收过程如下。
80+
81+
- G1 的年轻代回收,采用复制算法,并行进行收集,收集过程会 STW。
82+
83+
- G1 的老年代回收时也同时会对年轻代进行回收。主要分为四个阶段:
84+
85+
- 依然是初始标记阶段完成对根对象的标记,这个过程是STW的;
86+
87+
- 并发标记阶段,这个阶段是和用户线程并行执行的;
88+
- 最终标记阶段,完成三色标记周期;
89+
- 复制/清除阶段,这个阶段会优先对可回收空间较大的 Region 进行回收,即 garbage first,这也是 G1 名称的由来。
90+
91+
G1 采用每次只清理一部分而不是全部的 Region 的增量式清理,由此来保证每次 GC 停顿时间不会过长。
92+
93+
总结如下,G1 是逻辑分代不是物理划分,需要知道回收的过程和停顿的阶段。此外还需要知道,G1 算法允许通过 JVM 参数设置 Region 的大小,范围是 1~32MB,可以设置期望的最大 GC 停顿时间等。有兴趣读者也可以对 CMS 和 G1 使用的三色标记算法做简单了解。
94+
95+
##考察点
96+
97+
总结 JVM 相关的面试考察点如下:
98+
99+
1. 深入了解 JVM 的内存模型和 Java 的内存模型;
100+
101+
2. 要了解类的加载过程,了解双亲委派机制;
102+
103+
3. 要理解内存的可见性与 Java 内存模型对原子性、可见性、有序性的保证机制;
104+
105+
4. 要了解常用的 GC 算法的特点、执行过程,和适用场景,例如 G1 适合对最大延迟有要求的场合,ZGC 适用于 64 位系统的大内存服务中;
106+
107+
5. 要了解常用的 JVM 参数,明白对不同参数的调整会有怎样的影响,适用什么样的场景,例如垃圾回收的并发数、偏向锁设置等。
108+
109+
附录:JVM 相关的面试真题
110+
111+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/DB/CgotOV14luqALq0IAACqj_5S_nw868.png"alt="img"style="zoom:50%;" />
112+
113+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/BB/CgoB5l14luuAJqWRAACFJ6QM8Tg783.png"alt="img"style="zoom:50%;" />

‎docs/jvm/类加载机制.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
JVM 通过双亲委派模型进行类的加载,即当某个类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
44

5+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/BB/CgoB5l14luqAA8NAAABwXhjZrug069.png"alt="img"style="zoom:50%;" />
6+
57
**类加载器:**
68

79
1.**启动类加载器 (Bootstrap ClassLoader)**:负责加载 JAVA_HOME\lib 目录中的,或通过 - Xbootclasspath 参数指定路径中的,且被虚拟机认可(按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录也不会被加载)的类。启动类加载器无法被 Java 程序直接引用;
@@ -15,9 +17,14 @@ JVM 通过双亲委派模型进行类的加载,即当某个类加载器在接
1517

1618
1. 基础类的统一加载问题(越基础的类由越上层的加载器进行加载)。如类 java.lang.String,无论哪一个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,所以在程序的各种类加载器环境中都是同一个类。
1719
2. 提高 java 代码的安全性。比如说用户自定义了一个与系统库里同名的 java.lang.String 类,那么这个类就不会被加载,因为最顶层的类加载器会首先加载系统的 java.lang.String 类,而不会加载自定义的 String 类,防止了恶意代码的注入。
20+
3. 可以避免类的重复加载,另外也避免了 Java 的核心 API 被篡改。
21+
22+
1823

1924
#类加载流程
2025

26+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/DB/CgotOV14lumAWI3bAACVhLcSULk171.png"alt="img"style="zoom:50%;" />
27+
2128
类的生命周期会经历以下 7 个阶段:
2229

2330
-**加载阶段**
@@ -53,3 +60,5 @@ HotSpot 虚拟机在 JDK 1.7 之前都在方法区,而 JDK 1.8 之后此变量
5360

5461
初始化阶段 JVM 就正式开始执行类中编写的 Java 业务代码了。到这一步骤之后,类的加载过程就算正式完成了。
5562

63+
如上图所示,浅绿的两个部分表示类的生命周期,就是从类的加载到类实例的创建与使用,再到类对象不再被使用时可以被 GC 卸载回收。这里要注意一点,由 Java 虚拟机自带的三种类加载器加载的类在虚拟机的整个生命周期中是不会被卸载的,只有用户自定义的类加载器所加载的类才可以被卸载。
64+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp