Skip to content

Commit 23a5726

Browse files
committed
Java
1 parent b46dcf2 commit 23a5726

44 files changed

Lines changed: 1642 additions & 165 deletions

Some content is hidden

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

‎README.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,13 @@
263263
- [第十一节 DoS攻击](docs/Safety/11_DoS攻击.md)
264264
- [第十二节 重放攻击](docs/Safety/12_重放攻击.md)
265265

266-
## *3. 分布式
266+
## 3. 分布式
267+
268+
- [第一节 分布式系统设计理念](docs/distribution/1_分布式系统设计理念.md)
269+
- [第二节 CAP理论](docs/distribution/2_CAP理论.md)
270+
- [第三节 BASE理论](docs/distribution/3_BASE理论.md)
271+
- [第四节 分布式锁](docs/distribution/4_分布式锁.md)
272+
- [第五节 分布式事务](docs/distribution/5_分布式事务.md)
267273

268274
## *4. 微服务
269275

‎docs/JVM/1_JVM.md‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
## 运行时数据区域
1+
# 运行时数据区域
22

33
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/5778d113-8e13-4c53-b5bf-801e58080b97.png" width="400px"> </div>
44

5-
### 程序计数器(Program Counter Register)
5+
## 程序计数器(Program Counter Register)
66

77
- 当前线程所执行的字节码行号指示器(逻辑)
88
- 通过改变计数器的值来选取下一条需要执行的字节码指令
99
- 和线程一对一的关系,即“线程私有”
1010
- 对 Java 方法计数,如果是 Native 方法则计数器值为 Undefined
1111
- 只是计数,不会发生内存泄漏
1212

13-
### Java 虚拟机栈
13+
## Java 虚拟机栈
1414

1515
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
1616

@@ -57,15 +57,15 @@ javap -verbose JVMTest
5757

5858
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/j_2.png" > </div>
5959

60-
### 本地方法栈
60+
## 本地方法栈
6161

6262
本地方法栈与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
6363

6464
本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
6565

6666
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/66a6899d-c6b0-4a47-8569-9d08f0baf86c.png" width="300px"> </div>
6767

68-
### 堆
68+
## 堆
6969

7070
所有对象都在这里分配内存,是垃圾收集的主要区域("GC 堆")。
7171

@@ -132,7 +132,7 @@ java -Xms1M -Xmx2M HackTheJava
132132

133133

134134

135-
### 方法区
135+
## 方法区
136136

137137
用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
138138

@@ -156,19 +156,19 @@ HotSpot 虚拟机把它当成永久代来进行垃圾回收。但很难确定永
156156

157157
3、永久代会为 GC 带来不必要的复杂性
158158

159-
### 运行时常量池
159+
## 运行时常量池
160160

161161
运行时常量池是方法区的一部分。
162162

163163
Class 文件中的常量池(编译器生成的字面量和符号引用)会在类加载后被放入这个区域。
164164

165165
除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。
166166

167-
### 直接内存
167+
直接内存
168168

169169
在 JDK 1.4 中新引入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在堆内存和堆外内存来回拷贝数据。
170170

171-
### JVM常见参数
171+
## JVM常见参数
172172

173173
| 参数 | 含义 |
174174
| ---- | ------------------------------------------------------------ |

‎docs/JVM/2_JVM.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
## 二、HotSpot 虚拟机对象
1+
# HotSpot 虚拟机对象
22

3-
### 对象的创建
3+
## 对象的创建
44

55
对象的创建步骤:
66

@@ -52,7 +52,7 @@
5252
所以一般来说,执行 new 指令之后会接着执行 \<init \> 方法,
5353
把**对象按照程序员的意愿进行初始化**,这样一个真正可用的对象才算完全产生出来。
5454

55-
### 对象的内存布局
55+
## 对象的内存布局
5656

5757
在 Hotspot 虚拟机中,对象在内存中的布局可以分为 3 块区域:对象头、实例数据、对齐填充。
5858

@@ -79,7 +79,7 @@ Hotspot虚拟机的对象头包括两部分信息:
7979
换句话说就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或2倍),
8080
因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
8181

82-
### 对象的访问定位
82+
## 对象的访问定位
8383

8484
建立对象就是为了使用对象,我们的Java程序通过栈上的 reference 数据来操作堆上的具体对象。
8585
对象的访问方式视虚拟机的实现而定,目前主流的访问方式有两种:使用句柄、直接指针。

‎docs/JVM/3_JVM.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
## 三、String 类和常量池
1+
# String 类和常量池
22

3-
### 1、String 对象的两种创建方式
3+
## 1、String 对象的两种创建方式
44

55
```java
66
String str1 = "abcd";
@@ -19,7 +19,7 @@ System.out.println(str1==str2); //false
1919

2020
str1 指向常量池中的 “abcd”,而 str2 指向堆中的字符串对象。
2121

22-
### 2、intern() 方法
22+
## 2、intern() 方法
2323

2424
intern() 方法设计的初衷,就是重用 String 对象,以节省内存消耗。
2525

@@ -83,7 +83,7 @@ true
8383

8484
`String s4 = "11"`, 这一行代码会直接去常量池中创建,但是发现已经有这个对象了,此时 s4 就是指向 s3 引用对象的一个引用。因此 `s3 == s4 `返回了true。
8585

86-
### 3、字符串拼接
86+
## 3、字符串拼接
8787

8888
```java
8989
String str1 = "str";

‎docs/JVM/4_JVM.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 四、8 种基本类型的包装类和常量池
1+
# 8 种基本类型的包装类和常量池
22

33
- Java 基本类型的包装类的大部分都实现了常量池技术, 即Byte,Short,Integer,Long,Character,Boolean; 这 5 种包装类默认创建了数值 **[-128,127]** 的相应类型的缓存数据, 但是超出此范围仍然会去创建新的对象。
44
- **两种浮点数类型的包装类 Float , Double 并没有实现常量池技术**。

‎docs/JVM/5_JVM.md‎

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
## 垃圾收集
1+
# 垃圾收集
22

33
[垃圾回收的脑图](http://naotu.baidu.com/file/1eb8ce88025d3d160c2efbf03c7b62b5?token=64d1a334774221b1)
44

55
垃圾收集主要是针对堆和方法区进行。程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。
66

7-
### 判断一个对象是否可被回收
7+
## 判断一个对象是否可被回收
88

9-
#### 1. 引用计数算法
9+
### 1. 引用计数算法
1010

1111
为对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。
1212

@@ -34,7 +34,7 @@ public class Test {
3434
- 优点:执行效率高,程序执行受影响较小。
3535
- 缺点:无法检测出循环引用的情况,引起内存泄漏。
3636

37-
#### 2. 可达性分析算法
37+
### 2. 可达性分析算法
3838

3939
通过判断对象的引用链是否可达来决定对象是否可以被回收。
4040

@@ -50,7 +50,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般
5050

5151
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/83d909d2-3858-4fe1-8ff4-16471db0b180.png" width="350px"> </div>
5252

53-
#### 3. 方法区的回收
53+
### 3. 方法区的回收
5454

5555
因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,所以在方法区上进行回收性价比不高。
5656

@@ -64,7 +64,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般
6464
- 加载该类的 ClassLoader 已经被回收。
6565
- 该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
6666

67-
#### 4. finalize()
67+
### 4. finalize()
6868

6969
类似 C++ 的析构函数,用于关闭外部资源。但是 try-finally 等方式可以做得更好,并且该方法运行代价很高,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。
7070

@@ -77,13 +77,13 @@ Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般
7777
- 由于线程的优先级比较低,执行过程随时可能会被终止;
7878
- 给予对象最后一次重生的机会
7979

80-
### 引用类型
80+
## 引用类型
8181

8282
无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关。
8383

8484
Java 提供了四种强度不同的引用类型。
8585

86-
#### 1. 强引用
86+
### 1. 强引用
8787

8888
被强引用关联的对象不会被回收。
8989

@@ -95,7 +95,7 @@ Object obj = new Object();
9595

9696
抛出OOM Error终止程序也不会回收具有强引用的对象,只有通过将对象设置为null来弱化引用,才能使其被回收。
9797

98-
#### 2. 软引用
98+
### 2. 软引用
9999

100100
表示对象处在**有用但非必须**的状态。
101101

@@ -109,7 +109,7 @@ SoftReference<Object> sf = new SoftReference<Object>(obj);
109109
obj = null; // 使对象只被软引用关联
110110
```
111111

112-
#### 3. 弱引用
112+
### 3. 弱引用
113113

114114
表示非必须的对象,比软引用更弱一些。适用于偶尔被使用且不影响垃圾收集的对象。
115115

@@ -123,7 +123,7 @@ WeakReference<Object> wf = new WeakReference<Object>(obj);
123123
obj = null;
124124
```
125125

126-
#### 4. 虚引用
126+
### 4. 虚引用
127127

128128
又称为幽灵引用或者幻影引用,一个对象是否有虚引用的存在,不会对其生存时间造成影响,也无法通过虚引用得到一个对象。
129129

@@ -149,9 +149,9 @@ obj = null;
149149

150150
> 引用队列(ReferenceQueue):当GC(垃圾回收线程)准备回收一个对象时,如果发现它还仅有软引用(或弱引用,或虚引用)指向它,就会在回收该对象之前,把这个软引用(或弱引用,或虚引用)加入到与之关联的引用队列(ReferenceQueue)中。**如果一个软引用(或弱引用,或虚引用)对象本身在引用队列中,就说明该引用对象所指向的对象被回收了**。无实际的存储结构,存储逻辑依赖于内部节点之间的关系来表达。
151151
152-
### 垃圾收集算法
152+
## 垃圾收集算法
153153

154-
#### 1. 标记 - 清除
154+
### 1. 标记 - 清除
155155

156156
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/005b481b-502b-4e3f-985d-d043c2b330aa.png" width="400px"> </div>
157157

@@ -166,7 +166,7 @@ obj = null;
166166
- 标记和清除过程效率都不高;
167167
- 会产生大量不连续的内存碎片,导致无法给大对象分配内存。
168168

169-
#### 2. 标记 - 整理
169+
### 2. 标记 - 整理
170170

171171
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/ccd773a5-ad38-4022-895c-7ac318f31437.png" width="400px"> </div>
172172

@@ -180,7 +180,7 @@ obj = null;
180180

181181
- 需要移动大量对象,处理效率比较低。
182182

183-
#### 3. 复制
183+
### 3. 复制
184184

185185
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/b2b77b9e-958c-4016-8ae5-9c6edd83871e.png" width="400px"> </div>
186186

@@ -192,7 +192,7 @@ obj = null;
192192

193193
HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1,保证了内存的利用率达到 90%。如果每次回收有多于 10% 的对象存活,那么一块 Survivor 就不够用了,此时需要依赖于老年代进行空间分配担保,也就是借用老年代的空间存储放不下的对象。
194194

195-
#### 4. 分代收集
195+
### 4. 分代收集
196196

197197
Stop-the-World
198198

@@ -212,7 +212,7 @@ Safepoint
212212
- 新生代使用:复制算法
213213
- 老年代使用:标记 - 清除 或者 标记 - 整理 算法
214214

215-
### 垃圾收集器
215+
## 垃圾收集器
216216

217217
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div>
218218

@@ -221,7 +221,7 @@ Safepoint
221221
- 单线程与多线程:单线程指的是垃圾收集器只使用一个线程,而多线程使用多个线程;
222222
- 串行与并行:串行指的是垃圾收集器与用户程序交替执行,这意味着在执行垃圾收集的时候需要停顿用户程序;并行指的是垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式执行。
223223

224-
#### 1. Serial 收集器(-XX:+UseSerialGC)
224+
### 1. Serial 收集器(-XX:+UseSerialGC)
225225

226226
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div>
227227

@@ -233,15 +233,15 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
233233

234234
它是 Client 场景下的默认新生代收集器,因为在该场景下内存一般来说不会很大。它收集一两百兆垃圾的停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿时间是可以接受的。
235235

236-
#### 2. ParNew 收集器(-XX:+UseParNewGC)
236+
### 2. ParNew 收集器(-XX:+UseParNewGC)
237237

238238
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div>
239239

240240
它是 Serial 收集器的多线程版本。
241241

242242
它是 Server 场景下默认的新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合使用。
243243

244-
#### 3. Parallel Scavenge 收集器(-XX:+UseParallelGC)
244+
### 3. Parallel Scavenge 收集器(-XX:+UseParallelGC)
245245

246246
与 ParNew 一样是多线程收集器。
247247

@@ -253,7 +253,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
253253

254254
可以通过一个开关参数打开 GC 自适应的调节策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。
255255

256-
#### 4. Serial Old 收集器(-XX:+UseSerialOldGC)
256+
### 4. Serial Old 收集器(-XX:+UseSerialOldGC)
257257

258258
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div>
259259

@@ -262,15 +262,15 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
262262
- 在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。
263263
- 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。
264264

265-
#### 5. Parallel Old 收集器(-XX:+UseParallelOldGC)
265+
### 5. Parallel Old 收集器(-XX:+UseParallelOldGC)
266266

267267
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div>
268268

269269
是 Parallel Scavenge 收集器的老年代版本。
270270

271271
**在注重吞吐量以及 CPU 资源敏感的场合**,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。
272272

273-
#### 6. CMS 收集器(-XX:+UseConcMarkSweepGC)
273+
### 6. CMS 收集器(-XX:+UseConcMarkSweepGC)
274274

275275
<div align="center"> <img src="https://gitee.com/duhouan/ImagePro/raw/master/JVM/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div>
276276

@@ -293,7 +293,7 @@ CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。
293293
- 无法处理浮动垃圾,可能出现 Concurrent Mode Failure。浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。
294294
- 标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC。
295295

296-
#### 7. G1 收集器(-XX:+UseG1GC)
296+
### 7. G1 收集器(-XX:+UseG1GC)
297297

298298
G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器。
299299

@@ -327,9 +327,9 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
327327

328328

329329

330-
### 降低停顿时间
330+
## 降低停顿时间
331331

332-
#### 1. 使用 CMS 收集器
332+
### 1. 使用 CMS 收集器
333333

334334
CMS 收集器进行垃圾回收,有 4 个步骤:
335335

@@ -340,7 +340,7 @@ CMS 收集器进行垃圾回收,有 4 个步骤:
340340

341341
其中初始标记和重新标记需要 "stop the world",但耗时时间最长的并发标记、并发清除过程中,GC 线程都可与用户线程一起工作。整体上说,CMS 和用户线程是并行的。
342342

343-
#### 2. 增量算法
343+
### 2. 增量算法
344344

345345
基本思路:若一次性将所有垃圾进行处理,会造成系统长时间的停顿,则就让 GC 线程与用户线程交替执行。每次 GC 线程只收集一小块区域的内存空间,接着切换到用户线程,重复几次,直至 GC 完成。
346346

0 commit comments

Comments
 (0)