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

Commit9982e20

Browse files
committed
Merge remote-tracking branch 'origin/master'
# Conflicts:#README.md#_sidebar.md#docs/JVM/JMM保证.md#docs/JVM/JMM内存可见性.md
2 parents3fea06e +c36c8da commit9982e20

File tree

7 files changed

+376
-40
lines changed

7 files changed

+376
-40
lines changed

‎docs/InterviewGuide/Spring.md

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,14 @@
11
##Spring
22

3-
Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 SpringBoot,也是基于 Spring 实现的,SpringBoot 的诞生是为了让开发者更方便地使用 Spring,因此 Spring 在 Java 体系中的地位可谓首屈一指。
4-
当然,如果想要把 Spring 所有功能都讲的一清二楚,远远不是一两篇文章能够做到的,但幸运的是,Spring 的基础资料可以很轻易的搜索到,那么我们本讲主要的目的就是把 Spring 中的核心知识点和常见面试题分享给大家,希望对大家能有所帮助。
5-
63
###Spring 介绍
74

8-
Spring 是一个开源框架,为了解决企业应用程序开发复杂性而创建的,Spring 的概念诞生于 2002 年,于 2003 年正式发布第一个版本 Spring Framework 0.9。下面一起来看 Spring 各个版本的更新特性和它的发展变化吧。Spring 特性如下图所示:
9-
10-
<imgsrc="C:\Users\孙白胖的爸爸\AppData\Roaming\Typora\typora-user-images\image-20200720165026696.png"alt="image-20200720165026696"style="zoom:50%;" />
11-
12-
Spring 模块如下图所示:
13-
14-
<imgsrc="C:\Users\孙白胖的爸爸\AppData\Roaming\Typora\typora-user-images\image-20200720165200616.png"alt="image-20200720165200616"style="zoom:67%;" />
15-
16-
####Spring 1.x
17-
18-
此版本主要是为了解决企业应用程序开发复杂性而创建的,当时 J2EE 应用的经典架构是分层架构:表现层、业务层、持久层,最流行的组合就是 SSH(Struts、Spring、Hibernate)。
19-
Spring 1.x 仅支持基于 XML 的配置,确保用户代码不依赖 Spring,它主要包含了以下功能模块:aop、beans、ejb、jdbc、jndi、orm、transation、validation、web 等。
20-
21-
####Spring 2.x
22-
23-
Spring 2.x 的改动并不是很大,主要是在 Spring 1.x 的基础上增加了几个新模块,如 ehcache、jms、jmx、scripting、stereotype 等。
24-
25-
####Spring 3.x
5+
Spring 是一个开源框架,为了解决企业应用程序开发复杂性而创建的,Spring 的概念诞生于 2002 年,于 2003 年正式发布第一个版本 Spring Framework 0.9。下面一起来看 Spring 各个版本的更新特性和它的发展变化吧。
266

27-
Spring 3.x 开始不止支持 XML 的配置,还扩展了基于 Java 类的配置,还增加了 Expression、Instructment、Tomcat、oxm 等组件,同时将原来的 Web 细分为:Portlet、Servlet。
7+
![img](http://s0.lgstatic.com/i/image2/M01/8A/C6/CgoB5l14puyAXsN8AAB-CNBQpnQ843.png)
288

29-
####Spring4.x
9+
图中红框框住的是比较重要的组件,Core 组件是Spring所有组件的核心;Bean 组件和 Context 组件我刚才提到了,是实现 IoC 和依赖注入的基础;AOP 组件用来实现面向切面编程;Web 组件包括 SpringMVC,是 Web 服务的控制层实现。
3010

31-
Spring 4.x 扩充了 Groovy、Messaging、WebMvc、Tiles2、WebSocket 等功能组件,同时 Spring 还适配了 Java 版本,全面支持 Java 8.0、Lambda 表达式等。随着 RESTful 架构风格被越来越多的用户所采用,Spring 4.x 也提供了 RestController 等注解新特性。
32-
33-
####Spring 5.x
34-
35-
Spring 5.x 紧跟 Java 相关技术的更新迭代,不断适配 Java 的新版本,同时不断重构优化自身核心框架代码,支持函数式、响应式编程模型等。
11+
<imgsrc="http://s0.lgstatic.com/i/image2/M01/8A/C6/CgoB5l14puyAK0COAAGd_8jLTtQ986.png"alt="img"style="zoom:80%;" />
3612

3713
###Spring 核心
3814

@@ -46,7 +22,17 @@ Spring 核心包括以下三个方面:
4622

4723
####控制反转(IoC)
4824

49-
控制反转(Inversion of Control,IoC),Spring的控制反转指一个对象依赖的其他对象将会在容器的初始化完成后主动将其依赖的对象传递给它,而不需要这个对象自己创建或者查找其依赖的对象。Spring基于控制反转技术实现系统对象之间依赖的解耦。
25+
控制反转(Inversion of Control,IoC),Spring的控制反转指一个对象依赖的其他对象将会在容器的初始化完成后主动将其依赖的对象传递给它,而不需要这个对象自己创建或者查找其依赖的对象。Spring基于控制反转技术实现系统对象之间依赖的解耦。举个例子如下图,拿公司招聘岗位来举例。假设一个公司有产品、研发、测试等岗位。如果是公司根据岗位要求,逐个安排人选,如图中向下的箭头,这是正向流程。如果反过来,不用公司来安排候选人,而是由第三方猎头来匹配岗位和候选人,然后进行推荐,如图中向上的箭头,这就是控制反转。
26+
27+
![img](http://s0.lgstatic.com/i/image2/M01/8A/E6/CgotOV14puyAODLyAAAnwOuTkEk368.png)
28+
29+
在 Spring 中,对象的属性是由对象自己创建的,就是正向流程;如果属性不是对象创建,而是由 Spring 来自动进行装配,就是控制反转。这里的 DI 也就是依赖注入,就是实现控制反转的方式。正向流程导致了对象于对象之间的高耦合,IoC 可以解决对象耦合的问题,有利于功能的复用,能够使程序的结构变得非常灵活。
30+
31+
####Context 和 Bean
32+
33+
Spring 进行 IoC 实现时使用的两个概念:Context 上下文和 Bean。如下图所示,所有被 Spring 管理的、由 Spring 创建的、用于依赖注入的对象,就叫作一个 Bean。Spring 创建并完成依赖注入后,所有 Bean 统一放在一个叫作 Context 的上下文中进行管理。
34+
35+
![img](http://s0.lgstatic.com/i/image2/M01/8A/C6/CgoB5l14puyAWtEwAAA9kZ-6cDw595.png)
5036

5137
####依赖注入(DI)
5238

@@ -470,6 +456,8 @@ public void save() {
470456

471457
答:Spring 中 Bean 的生命周期如下:
472458

459+
![img](http://s0.lgstatic.com/i/image2/M01/8A/C6/CgoB5l14puyAAa1gAABPP0lufvQ678.png)
460+
473461
- ① 实例化 Bean:对于 BeanFactory 容器,当客户向容器请求一个尚未初始化的 Bean 时,或初始化 Bean 的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean 进行实例化。对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 Bean;
474462
- ② 设置对象属性(依赖注入):实例化后的对象被封装在 BeanWrapper 对象中,紧接着 Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入;
475463
- ③ 处理 Aware 接口:Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 Bean:

‎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