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

Commit a192e7f

Browse files
突破Java面试系列
0 parents commit a192e7f

File tree

163 files changed

+26105
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+26105
-0
lines changed

‎Java/JAVA-Calendar.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
Calendar.getInstance() 中所获得的实例就是一个 "GreogrianCalendar" 对象(与通过 new GregorianCalendar() 获得的结果一致)。
2+
3+
#Calendar 与 Date 的转换
4+
Calendar calendar = Calendar.getInstance();
5+
// 从一个 Calendar 对象中获取 Date 对象
6+
Date date = calendar.getTime();
7+
// 将 Date 对象反应到一个 Calendar 对象中,
8+
// Calendar/GregorianCalendar 没有构造函数可以接受 Date 对象
9+
// 所以我们必需先获得一个实例,然后设置 Date 对象
10+
calendar.setTime(date);
11+
#注意的事项:
12+
##1. Calendar 的 set() 方法
13+
14+
set(int field, int value) - 是用来设置"年/月/日/小时/分钟/秒/微秒"等值
15+
16+
field 的定义在 Calendar 中
17+
18+
set(int year, int month, int day, int hour, int minute, int second) 但没有
19+
20+
set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不会自动将 MilliSecond 清为 0。
21+
22+
另外,月份的起始值为0而不是1,所以要设置八月时,我们用7而不是8。
23+
24+
calendar.set(Calendar.MONTH, 7);
25+
26+
我们通常需要在程序逻辑中将它清为 0, Calendar 不是马上就刷新其内部的记录
27+
28+
在 Calendar 的方法中,get() 和 add() 会让 Calendar 立刻刷新。Set() 的这个特性会给我们的开发带来一些意想不到的结果。
29+
##add() 与 roll() 的区别
30+
31+
add() 的功能非常强大,add 可以对 Calendar 的字段进行计算。如果需要减去值,那么使用负数值就可以了,如 add(field, -value)。
32+
33+
add() 有两条规则:
34+
35+
当被修改的字段超出它可以的范围时,那么比它大的字段会自动修正。如:
36+
Calendar cal1 = Calendar.getInstance();
37+
cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
38+
cal1.add(Calendar.MONTH, 1); //2000-9-31 => 2000年10月1日,对吗?
39+
System.out.println(cal1.getTime()); //结果是 2000年9月30日
40+
41+
另一个规则是,如果比它小的字段是不可变的(由 Calendar 的实现类决定),那么该小字段会修正到变化最小的值。
42+
43+
以上面的例子,9-31 就会变成 9-30,因为变化最小。
44+
45+
Roll() 的规则只有一条:
46+
当被修改的字段超出它可以的范围时,那么比它大的字段不会被修正。如:
47+
48+
Calendar cal1 = Calendar.getInstance();
49+
cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日
50+
cal1.roll(Calendar.WEEK_OF_MONTH, -1); //1999-6-1, 周二
51+
cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日
52+
cal1.add(Calendar.WEEK_OF_MONTH, -1); //1999-5-30, 周日
53+
WEEK_OF_MONTH 比 MONTH 字段小,所以 roll 不能修正 MONTH 字段。

‎Java/JVM/JVM实战---内存模型.md

Lines changed: 403 additions & 0 deletions
Large diffs are not rendered by default.

‎Java/JVM/JVM实战---垃圾收集器.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
使用分代垃圾收集器,基于以下观察事实(弱分代假设)
2+
- 大多数分配对象的存活时间短
3+
- 存活时间久的对象很少引用存活时间短的对象
4+
5+
由此, HotSpot VM 将堆分为两个物理区空间,这就是分代(永久代只存储元数据, eg. 类的数据结构,保留字符串( Interned String))
6+
7+
8+
根据新生代和老年代各自的特点,我们应该分别为它们选择不同的收集器,以提升垃圾回收效率.
9+
![](http://upload-images.jianshu.io/upload_images/4685968-3a367913acebef67.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
10+
11+
# 1 新生代垃圾收集器
12+
13+
## 1.1 Serial垃圾收集器
14+
一个主要应用于Y-GC的垃圾回收器,采用串行单线程的方式完成GC任务,其中"Stop The World"简称STW,即垃圾回收的某个阶段会暂停整个应用程序的执行
15+
F-GC的时间相对较长,频繁FGC会严重影响应用程序的性能
16+
![Serial 回收流程](https://upload-images.jianshu.io/upload_images/4685968-407a95f442c62819.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
17+
`单线程 Stop-The-World 式`
18+
![](http://upload-images.jianshu.io/upload_images/4685968-ebdf41221960630c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
19+
- 单线程
20+
只会使用一个CPU或一条GC线程进行GC,并且在GC过程中暂停其他所有的工作线程,因此用户的请求或图形化界面会出现卡顿
21+
- 适合Client模式
22+
一般客户端应用所需内存较小,不会创建太多的对象,而且堆内存不大,因此GC时间比较短,即使在这段时间停止一切用户线程,也不会感到明显停顿
23+
- 简单高效
24+
由于Serial收集器只有一条GC线程,避免了线程切换的开销
25+
- 采用"复制"算法
26+
## 1.2 ParNew垃圾收集器
27+
ParNew是Serial的多线程版本.
28+
![](http://upload-images.jianshu.io/upload_images/4685968-e4947c56e4c734f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
29+
## 2.1 多线程并行执行
30+
ParNew由多条GC线程并行地进行垃圾清理.
31+
但清理过程仍然需要暂停一切其他用户线程.
32+
但由于有多条GC线程同时清理,清理速度比Serial有一定的提升
33+
## 2.2 适合多CPU的服务器环境
34+
由于使用多线程,是许多运行在 server 模式下的虚拟机首选的新生代收集器
35+
- 与Serial性能对比
36+
ParNew和Serial唯一区别就是使用了多线程垃圾回收,在多CPU的环境下性能比Serial会有一定程度的提升
37+
但线程切换需要额外的开销,因此在单CPU环境中表现不如Serial,双CPU环境也不一定就比Serial高效
38+
默认开启的收集线程数与CPU数量相同
39+
## 2.3 采用"复制"算法
40+
## 2.4 追求"降低停顿时间"
41+
和Serial相比,ParNew使用多线程的目的就是缩短GC时间,从而减少用户线程被停顿的时间
42+
# 3 Parallel : 吞吐量为先!
43+
## 3.1 Scavenge垃圾收集器
44+
Parallel Scavenge和ParNew一样都是并行的多线程、新生代收集器,都使用"复制"算法(`Stop-The-World`)进行垃圾回收
45+
46+
但它们有个巨大不同点:
47+
- ParNew收集器追求降低GC时用户线程的停顿时间,适合交互式应用,良好的反应速度提升用户体验.
48+
- Parallel Scavenge追求可控的CPU吞吐量,能够在较短的时间内完成指定任务,适合不需太多交互的后台运算
49+
50+
>吞吐量是指用户线程运行时间占CPU总时间的比例.
51+
>CPU总时间包括 : 用户线程运行时间 和 GC线程运行的时间.
52+
> 因此,吞吐量越高表示用户线程运行时间越长,从而用户线程能够被快速处理完.
53+
54+
- 降低停顿时间的两种方式
55+
1.在多CPU环境中使用多条GC线程,从而垃圾回收的时间减少,从而用户线程停顿的时间也减少;
56+
2.实现GC线程与用户线程并发执行。所谓并发,就是用户线程与GC线程交替执行,从而每次停顿的时间会减少,用户感受到的停顿感降低,但线程之间不断切换意味着需要额外的开销,从而垃圾回收和用户线程的总时间将会延长。
57+
58+
- Parallel Scavenge提供的参数
59+
- -XX:GCTimeRadio
60+
直接设置吞吐量大小,GC时间占总时间比率.相当于是吞吐量的倒数.
61+
62+
- -XX:MaxGCPauseMillis
63+
设置最大GC停顿时间
64+
Parallel Scavenge会根据这个值的大小确定新生代的大小.
65+
这个值越小,新生代就越小,从而收集器就能以较短时间进行一次GC
66+
但新生代变小后,回收的频率就会提高,吞吐量也降下来了,因此要合理控制这个值
67+
- -XX:+UseAdaptiveSizePolicy
68+
开启GC **自适应的调节策略(区别于ParNew)**.
69+
我们只要设置最大堆(-Xmx)和MaxGCPauseMillis或GCTimeRadio,收集器会自动调整新生代的大小、Eden和Survior的比例、对象进入老年代的年龄,以最大程度上接近我们设置的MaxGCPauseMillis或GCTimeRadio
70+
## 3.2 Old垃圾收集器
71+
Parallel Scavenge的老年代版本,一般它们搭配使用,追求CPU吞吐量
72+
73+
它们在垃圾收集时都是由多条GC线程并行执行,并暂停一切用户线程,使用"标记-整理"算法.因此,由于在GC过程中没有使垃圾收集和用户线程并行执行,因此它们是追求吞吐量的垃圾收集器.
74+
![](http://upload-images.jianshu.io/upload_images/4685968-7dfdda76a61a31cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
75+
# **老年代垃圾收集器**
76+
# 1 Serial Old垃圾收集器
77+
Serial的老年代版本,都是单线程收集器,GC时只启动一条GC线程,因此都适合客户端应用.
78+
79+
80+
它们唯一的区别就是
81+
- Serial Old工作在老年代,使用"标记-整理"算法
82+
- Serial工作在新生代,使用"复制"算法.
83+
![](http://upload-images.jianshu.io/upload_images/4685968-b150a60a1bae36a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
84+
85+
# 4 CMS垃圾收集器(Concurrent Mark Sweep Collector) : 低延迟为先!
86+
回收停顿时间比较短、目前比较常用的垃圾回收器。它通过初始标记(InitialMark)、并发标记(Concurrent Mark)、重新标记( Remark)、并发清除( Concurrent Sweep )四个步骤完成垃圾回收工作
87+
由于CMS采用的是"标记-清除算法",因此戸生大量的空间碎片。为了解决这个问题,CMS可以通过配置
88+
```
89+
-XX:+UseCMSCompactAtFullCollection
90+
```
91+
参数,强制JVM在FGC完成后対老年代迸行圧縮,执行一次空间碎片整理,但是空间碎片整理阶段也会引发STW。为了减少STW次数,CMS还可以通过配置
92+
```
93+
-XX:+CMSFullGCsBeforeCompaction=n
94+
```
95+
参数,在执行了n次FGC后, JVM再在老年代执行空间碎片整理
96+
97+
对许多应用来说,快速响应比端到端的吞吐量更为重要
98+
99+
管理新生代的方法与 parallel 和 serial 相同
100+
在老年代则尽可能并发执行,每个 GC 周期只有2次短的停顿
101+
102+
一种追求最短停顿时间的收集器
103+
在GC时使得用户线程和GC线程并发执行,因此在GC过程中用户也不会感受到明显卡顿
104+
但用户线程和GC线程之间不停地切换会有额外的开销,因此垃圾回收总时间就会被延长
105+
**垃圾回收过程**
106+
前两步需要"Stop The World"
107+
- 初始标记 (Initial Mark)
108+
停止一切用户线程,仅使用一条初始标记线程对所有与GC Roots直接相关联的 老年代对象进行标记,速度很快
109+
- 并发标记 (Concurrent Marking Phase)
110+
使用多条并发标记线程并行执行,并与用户线程并发执行.此过程进行可达性分析,标记所有这些对象可达的存货对象,速度很慢
111+
- 重新标记 ( Remark)
112+
因为并发标记时有用户线程在执行,标记结果可能有变化
113+
停止一切用户线程,并使用多条重新标记线程并行执行,重新遍历所有在并发标记期间有变化的对象进行最后的标记.这个过程的运行时间介于初始标记和并发标记之间
114+
- 并发清除 (Concurrent Sweeping)
115+
只使用一条并发清除线程,和用户线程们并发执行,清除刚才标记的对象
116+
这个过程非常耗时
117+
![](http://upload-images.jianshu.io/upload_images/4685968-fb1723e25639cf21.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
118+
## 4.1 **CMS的缺点**
119+
- 吞吐量低
120+
由于CMS在GC过程用户线程和GC线程并行,从而有线程切换的额外开销
121+
因此CPU吞吐量就不如在GC过程中停止一切用户线程的方式来的高
122+
- 无法处理浮动垃圾,导致频繁Full GC
123+
由于垃圾清除过程中,用户线程和GC线程并发执行,也就是用户线程仍在执行,那么在执行过程中会产生垃圾,这些垃圾称为"浮动垃圾"
124+
如果CMS在GC过程中,用户线程需要在老年代中分配内存时发现空间不足,就需再次发起Full GC,而此时CMS正在进行清除工作,因此此时只能由Serial Old临时对老年代进行一次Full GC
125+
- 使用"标记-清除"算法产生碎片空间
126+
由于CMS使用了"标记-清除"算法, 因此清除之后会产生大量的碎片空间,不利于空间利用率.不过CMS提供了应对策略:
127+
- 开启-XX:+UseCMSCompactAtFullCollection
128+
开启该参数后,每次FullGC完成后都会进行一次内存压缩整理,将零散在各处的对象整理到一块儿.但每次都整理效率不高,因此提供了以下参数.
129+
- 设置参数-XX:CMSFullGCsBeforeCompaction
130+
本参数告诉CMS,经过了N次Full GC过后再进行一次内存整理.
131+
132+
# 5 G1收集器(Garbage-First)
133+
Hotspot 在JDK7中推出了新一代 G1 ( Garbage-First Garbage Collector )垃圾回收,通过
134+
```
135+
-XX:+UseG1GC
136+
```
137+
参数启用
138+
和CMS相比,Gl具备压缩功能,能避免碎片向題,G1的暂停时间更加可控。性能总体还是非常不错的,G1是当今最前沿的垃圾收集器成果之一.
139+
140+
## 5.1 G1的特点
141+
- 追求停顿时间
142+
- 多线程GC
143+
- 面向服务端应用
144+
- 整体来看基于标记-整理和局部来看基于复制算法合并
145+
不会产生内存空间碎片
146+
- 可对整个堆进行垃圾回收
147+
- 可预测的停顿时间
148+
## 5.2 G1的内存模型
149+
没有新生代和老年代的概念,而是将Java堆划分为一块块独立的大小相等的Region.
150+
当要进行垃圾收集时,首先估计每个Region中的垃圾数量,每次都从垃圾回收价值最大的Region开始回收,因此可以获得最大的回收效率
151+
![](https://upload-images.jianshu.io/upload_images/4685968-db8d827f816cca34.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
152+
G1将Java堆空间分割成了若干相同大小的区域,即region
153+
包括
154+
- Eden
155+
- Survivor
156+
- Old
157+
- Humongous
158+
159+
其中,`Humongous `是特殊的Old类型,专门放置大型对象.
160+
这样的划分方式意味着不需要一个连续的内存空间管理对象.G1将空间分为多个区域,**优先回收垃圾最多**的区域.
161+
G1采用的是**Mark-Copy** ,有非常好的空间整合能力,不会产生大量的空间碎片
162+
G1的一大优势在于可预测的停顿时间,能够尽可能快地在指定时间内完成垃圾回收任务
163+
在JDK11中,已经将G1设为默认垃圾回收器,通过jstat命令可以查看垃圾回收情况,在YGC时S0/S1并不会交换.
164+
165+
## 5.3 Remembered Set
166+
一个对象和它内部所引用的对象可能不在同一个Region中,那么当垃圾回收时,是否需要扫描整个堆内存才能完整地进行一次可达性分析?
167+
当然不是,每个Region都有一个Remembered Set,用于记录本区域中所有对象引用的对象所在的区域,从而在进行可达性分析时,只要在GC Roots中再加上Remembered Set即可防止对所有堆内存的遍历.
168+
## 5.4 G1垃圾收集过程
169+
170+
- 初始标记
171+
标记与GC Roots直接关联的对象,停止所有用户线程,只启动一条初始标记线程,这个过程很快.
172+
- 并发标记
173+
进行全面的可达性分析,开启一条并发标记线程与用户线程并行执行.这个过程比较长.
174+
- 最终标记
175+
标记出并发标记过程中用户线程新产生的垃圾.停止所有用户线程,并使用多条最终标记线程并行执行.
176+
- 筛选回收
177+
回收废弃的对象.此时也需要停止一切用户线程,并使用多条筛选回收线程并行执行.
178+
![这里写图片描述](http://upload-images.jianshu.io/upload_images/4685968-0ea2b3a18ecc561a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
179+
180+
S0/S1的功能由G1中的Survivor region来承载,通过GC日志可以观察到完整的垃圾回收过程如下,其中就有Survivor regions的区域从0个到1个
181+
![](https://upload-images.jianshu.io/upload_images/4685968-ad5f6b99b3de502e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
182+
红色标识的为G1中的四种region,都处于Heap中.
183+
G1执行时使用4个worker并发执行,在初始标记时,还是会触发STW,如第一步所示的Pause
184+
185+
186+
187+
188+
189+
190+
191+
192+
193+
194+
195+
196+
197+
198+
199+
200+
201+
202+
203+
204+
205+
206+
207+
208+
209+
210+
211+
212+
213+
214+
215+
216+
217+
218+
219+
220+
221+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /