Skip to content

Commit 156db24

Browse files
committed
update
1 parent bc29969 commit 156db24

21 files changed

+174
-163
lines changed

Java/JVM.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Java 内存模型(JMM)是基于共享内存的多线程通信机制。
9090

9191
JVM内存结构 = 类加载器 + 执行引擎 + 运行时数据区域 。
9292

93-
![image-20210905150636105](https://gitee.com/tysondai/img/raw/master/image-20210905150636105.png)
93+
![image-20210905150636105](https://raw.githubusercontent.com/Tyson0314/img/master/image-20210905150636105.png)
9494

9595
> 图片来源:深入理解Java虚拟机-周志明
9696
@@ -172,11 +172,11 @@ JDK 1.8 的时候,HotSpot 的永久代被彻底移除了,使用元空间替
172172

173173
运行时常量池是方法区的一部分,在类加载之后,会将编译器生成的各种字面量和符号引号放到运行时常量池。在运行期间动态生成的常量,如 String 类的 intern()方法,也会被放入运行时常量池。
174174

175-
![](https://gitee.com/tysondai/img/raw/master/string-new.png)
175+
![](https://raw.githubusercontent.com/Tyson0314/img/master/string-new.png)
176176

177-
![](https://gitee.com/tysondai/img/raw/master/string-intern.png)
177+
![](https://raw.githubusercontent.com/Tyson0314/img/master/string-intern.png)
178178

179-
![](https://gitee.com/tysondai/img/raw/master/string-equal.png)
179+
![](https://raw.githubusercontent.com/Tyson0314/img/master/string-equal.png)
180180

181181
> 图片来源:https://blog.csdn.net/soonfly
182182
@@ -194,11 +194,11 @@ Java 程序通过栈上的 reference 数据来操作堆上的具体对象。对
194194

195195
- 如果使用句柄的话,那么 Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。
196196

197-
![](https://gitee.com/tysondai/img/raw/master/object-handle.png)
197+
![](https://raw.githubusercontent.com/Tyson0314/img/master/object-handle.png)
198198

199199
- 直接指针。reference 中存储的直接就是对象的地址。对象包含到对象类型数据的指针,通过这个指针可以访问对象类型数据。使用直接指针访问方式最大的好处就是访问对象速度快,它节省了一次指针定位的时间开销,虚拟机hotspot主要是使用直接指针来访问对象。
200200

201-
![](https://gitee.com/tysondai/img/raw/master/direct-pointer.png)
201+
![](https://raw.githubusercontent.com/Tyson0314/img/master/direct-pointer.png)
202202

203203

204204

@@ -245,7 +245,7 @@ ClassFile {
245245

246246
加载、验证、准备、解析、初始化、使用和卸载。
247247

248-
![](https://gitee.com/tysondai/img/raw/master/image-20210905002423703.png)
248+
![](https://raw.githubusercontent.com/Tyson0314/img/master/image-20210905002423703.png)
249249

250250
## 类加载的过程
251251

@@ -281,7 +281,7 @@ ClassFile {
281281

282282
一个类加载器收到一个类的加载请求时,它首先不会自己尝试去加载它,而是把这个请求委派给父类加载器去完成,这样层层委派,因此所有的加载请求最终都会传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
283283

284-
![](https://gitee.com/tysondai/img/raw/master/image-20210905002827546.png)
284+
![](https://raw.githubusercontent.com/Tyson0314/img/master/image-20210905002827546.png)
285285

286286
双亲委派模型的好处:可以防止内存中出现多份同样的字节码。如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,多个类加载器都去加载这个类到内存中,系统中将会出现多个不同的Object类,那么类之间的比较结果及类的唯一性将无法保证。
287287

@@ -339,7 +339,7 @@ public abstract class ClassLoader {
339339

340340
堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断那些对象已经死亡(即不能再被任何途径使用的对象)。
341341

342-
![](https://gitee.com/tysondai/img/raw/master/object-dead.png)
342+
![](https://raw.githubusercontent.com/Tyson0314/img/master/object-dead.png)
343343

344344
### 引用计数法
345345

@@ -365,7 +365,7 @@ public class ReferenceCountingGc {
365365

366366
通过GC Root对象为起点,从这些节点向下搜索,搜索所走过的路径叫引用链,当一个对象到GC Root没有任何的引用链相连时,说明这个对象是不可用的。
367367

368-
![](https://gitee.com/tysondai/img/raw/master/gc-root-refer.png)
368+
![](https://raw.githubusercontent.com/Tyson0314/img/master/gc-root-refer.png)
369369

370370
#### 可作为GC Roots的对象
371371

@@ -469,13 +469,13 @@ public class ReferenceCountingGc {
469469

470470
标记清除算法就是分为“标记”和“清除”两个阶段。标记出所有需要回收的对象,标记结束后统一回收所有被标记的对象。这种垃圾回收算法效率较低,并且会产生大量不连续的空间碎片。
471471

472-
![](https://gitee.com/tysondai/img/raw/master/image-20210905003458130.png)
472+
![](https://raw.githubusercontent.com/Tyson0314/img/master/image-20210905003458130.png)
473473

474474
### 复制清除算法
475475

476476
半区复制,用于新生代垃圾回收。将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。
477477

478-
![](https://gitee.com/tysondai/img/raw/master/image-20210905003714551.png)
478+
![](https://raw.githubusercontent.com/Tyson0314/img/master/image-20210905003714551.png)
479479

480480
特点:实现简单,运行高效,但可用内存缩小为了原来的一半,浪费空间。
481481

@@ -534,15 +534,15 @@ java -XX:+PrintCommandLineFlags -version
534534

535535
单线程收集器,使用一条垃圾收集线程去完成垃圾收集工作,在进行垃圾收集工作的时候必须暂停其他所有的工作线程( "Stop The World" ),直到它收集结束。
536536

537-
![](https://gitee.com/tysondai/img/raw/master/serial-collector.png)
537+
![](https://raw.githubusercontent.com/Tyson0314/img/master/serial-collector.png)
538538

539539
特点:简单高效;内存消耗最小;没有线程交互的开销,单线程收集效率高;需暂停所有的工作线程,用户体验不好。
540540

541541
### ParNew 收集器
542542

543543
Serial 收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和 Serial 收集器完全一样。
544544

545-
![](https://gitee.com/tysondai/img/raw/master/parnew-collector.png)
545+
![](https://raw.githubusercontent.com/Tyson0314/img/master/parnew-collector.png)
546546

547547
除了 Serial 收集器外,只有它能与 CMS 收集器配合工作。
548548

@@ -582,7 +582,7 @@ Concurrent Mark Sweep 并发标记清除,目的是获取最短应用停顿时
582582
- 重新标记: 在并发标记期间对象的引用关系可能会变化,需要重新进行标记。此阶段也会stw,停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。
583583
- 并发清除:清除死亡对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
584584

585-
![](https://gitee.com/tysondai/img/raw/master/cms-collector.png)
585+
![](https://raw.githubusercontent.com/Tyson0314/img/master/cms-collector.png)
586586

587587
由于在整个过程中耗时最长的并发标记和并发清除阶段中,垃圾收集器线程都可以与用户线程一起工作,所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
588588

@@ -607,7 +607,7 @@ G1垃圾收集器的目标是用在多核、大内存的机器上,在不同应
607607

608608
G1将整个堆分成相同大小的分区(Region),有四种不同类型的分区:Eden、Survivor、Old和Humongous(大对象)。分区的大小取值范围为1M到32M,都是2的幂次方。Region大小可以通过`-XX:G1HeapRegionSize`参数指定。Humongous区域用于存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。
609609

610-
![](https://gitee.com/tysondai/img/raw/master/g1-region.jpg)
610+
![](https://raw.githubusercontent.com/Tyson0314/img/master/g1-region.jpg)
611611

612612
G1 收集器对各个Region回收所获得的空间大小和回收所需时间的经验值进行排序,得到一个优先级列表,每次根据用户设置的最大的回收停顿时间(使用参数-XX:MaxGCPauseMillis指定,默认值是200毫秒),优先处理回收价值最大的 Region。
613613

Java/JVM高频面试题.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
JVM内存结构分为5大区域,**程序计数器****虚拟机栈****本地方法栈********方法区**
5151

52-
![](https://gitee.com/tysondai/img/raw/master/jvm内存结构0.png)
52+
![](https://raw.githubusercontent.com/Tyson0314/img/master/jvm内存结构0.png)
5353

5454
### 程序计数器
5555

@@ -185,7 +185,7 @@ ClassFile {
185185

186186
类的加载指的是将类的`class`文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个此类的对象,通过这个对象可以访问到方法区对应的类信息。
187187

188-
![](https://gitee.com/tysondai/img/raw/master/类加载.png)
188+
![](https://raw.githubusercontent.com/Tyson0314/img/master/类加载.png)
189189

190190
**加载**
191191

@@ -213,7 +213,7 @@ ClassFile {
213213

214214
一个类加载器收到一个类的加载请求时,它首先不会自己尝试去加载它,而是把这个请求**委派**给父类加载器去完成,这样层层委派,因此所有的加载请求最终都会传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
215215

216-
![](https://gitee.com/tysondai/img/raw/master/双亲委派.png)
216+
![](https://raw.githubusercontent.com/Tyson0314/img/master/双亲委派.png)
217217

218218
双亲委派模型的具体实现代码在 `java.lang.ClassLoader`中,此类的 `loadClass()` 方法运行过程如下:先检查类是否已经加载过,如果没有则让父类加载器去加载。当父类加载器加载失败时抛出 `ClassNotFoundException`,此时尝试自己去加载。源码如下:
219219

@@ -312,7 +312,7 @@ public class ReferenceCount {
312312

313313
通过`GC Root`对象为起点,从这些节点向下搜索,搜索所走过的路径叫引用链,当一个对象到`GC Root`没有任何的引用链相连时,说明这个对象是不可用的。
314314

315-
![](https://gitee.com/tysondai/img/raw/master/可达性分析0.png)
315+
![](https://raw.githubusercontent.com/Tyson0314/img/master/可达性分析0.png)
316316

317317
## 可作为GC Roots的对象有哪些?
318318

@@ -413,7 +413,7 @@ GC(`Garbage Collection`),垃圾回收,是Java与C++的主要区别之一
413413

414414
首先利用可达性去遍历内存,把存活对象和垃圾对象进行标记。标记结束后统一将所有标记的对象回收掉。这种垃圾回收算法效率较低,并且会**产生大量不连续的空间碎片**
415415

416-
![](https://gitee.com/tysondai/img/raw/master/标记清除.png)
416+
![](https://raw.githubusercontent.com/Tyson0314/img/master/标记清除.png)
417417

418418
**复制清除算法**
419419

@@ -425,7 +425,7 @@ GC(`Garbage Collection`),垃圾回收,是Java与C++的主要区别之一
425425

426426
根据老年代的特点提出的一种标记算法,标记过程仍然与`标记-清除`算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。
427427

428-
![](https://gitee.com/tysondai/img/raw/master/标记整理.png)
428+
![](https://raw.githubusercontent.com/Tyson0314/img/master/标记整理.png)
429429

430430
**分类收集算法**
431431

@@ -508,7 +508,7 @@ G1垃圾收集器的目标是在不同应用场景中**追求高吞吐量和低
508508

509509
G1将整个堆分成相同大小的分区(`Region`),有四种不同类型的分区:`Eden、Survivor、Old和Humongous`。分区的大小取值范围为 1M 到 32M,都是2的幂次方。分区大小可以通过`-XX:G1HeapRegionSize`参数指定。`Humongous`区域用于存储大对象。G1规定只要大小超过了一个分区容量一半的对象就认为是大对象。
510510

511-
![](https://gitee.com/tysondai/img/raw/master/g1分区.png)
511+
![](https://raw.githubusercontent.com/Tyson0314/img/master/g1分区.png)
512512

513513
G1 收集器对各个分区回收所获得的空间大小和回收所需时间的经验值进行排序,得到一个优先级列表,每次根据用户设置的最大回收停顿时间,优先回收价值最大的分区。
514514

Java/Java基础.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ Class 类提供了一些方法,可以获取成员变量、成员方法、接
976976

977977
Field提供了类和接口中字段的信息,通过Field类可以动态访问这些字段。下图是Field类提供的一些方法。
978978

979-
![field-method](https://gitee.com/tysondai/img/raw/master/field-method.png)
979+
![field-method](https://raw.githubusercontent.com/Tyson0314/img/master/field-method.png)
980980

981981
## Method类
982982

@@ -1101,7 +1101,7 @@ public class GenericMethod {
11011101

11021102
Throwable类是Error和Exception的父类,只有继承于Throwable的类或者其子类才能被抛出。Throwable分为两类:
11031103

1104-
![exception](https://gitee.com/tysondai/img/raw/master/exception.png)
1104+
![exception](https://raw.githubusercontent.com/Tyson0314/img/master/exception.png)
11051105

11061106
- Error:JVM 无法解决的严重问题,如栈溢出(StackOverflowError)、内存溢出(OOM)等。程序无法处理的错误。
11071107

@@ -1198,7 +1198,7 @@ public class ExceptionTest {
11981198

11991199
Java IO流的核心就是对文件的操作,对于字节 、字符类型的输入和输出流。IO流主要分为两大类,字节流和字符流。字节流可以处理任何类型的数据,如图片,视频等,字符流只能处理字符类型的数据。
12001200

1201-
![io](https://gitee.com/tysondai/img/raw/master/io.jpg)
1201+
![io](https://raw.githubusercontent.com/Tyson0314/img/master/io.jpg)
12021202

12031203
> 图片参考:[Java io学习整理](https://zhuanlan.zhihu.com/p/25418336)
12041204
@@ -1251,13 +1251,13 @@ OutputStreamWriter:字符到字节的转换,可对读取到的字符数据
12511251

12521252
同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
12531253

1254-
![bio](https://gitee.com/tysondai/img/raw/master/bio.png)
1254+
![bio](https://raw.githubusercontent.com/Tyson0314/img/master/bio.png)
12551255

12561256
## NIO
12571257

12581258
NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
12591259

1260-
![nio](https://gitee.com/tysondai/img/raw/master/nio.png)
1260+
![nio](https://raw.githubusercontent.com/Tyson0314/img/master/nio.png)
12611261

12621262
NIO与IO区别:
12631263

Java/Java基础面试题.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101

102102
**JVM** :英文名称(Java Virtual Machine),就是我们耳熟能详的 Java 虚拟机。Java 能够跨平台运行的核心在于 JVM 。
103103

104-
![](https://gitee.com/tysondai/img/raw/master/20220402230447.png)
104+
![](https://raw.githubusercontent.com/Tyson0314/img/master/20220402230447.png)
105105

106106
所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。也就是说class文件并不直接与机器的操作系统交互,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
107107

@@ -111,7 +111,7 @@
111111

112112
英文名称(Java Runtime Environment),就是Java 运行时环境。我们编写的Java程序必须要在JRE才能运行。它主要包含两个部分,JVM 和 Java 核心类库。
113113

114-
![](https://gitee.com/tysondai/img/raw/master/20220401234008.png)
114+
![](https://raw.githubusercontent.com/Tyson0314/img/master/20220401234008.png)
115115

116116
JRE是Java的运行环境,并不是一个开发环境,所以没有包含任何开发工具,如编译器和调试器等。
117117

@@ -141,7 +141,7 @@ JRE = JVM + Java 核心类库
141141

142142
JDK = JRE + Java工具 + 编译器 + 调试器
143143

144-
![](https://gitee.com/tysondai/img/raw/master/20220402230613.png)
144+
![](https://raw.githubusercontent.com/Tyson0314/img/master/20220402230613.png)
145145

146146
## 面向对象有哪些特性?
147147

@@ -1030,7 +1030,7 @@ unchecked Exception:
10301030

10311031
不同的线程干专业的事情,最终每个线程都没空着,系统的吞吐量自然就上去了。
10321032

1033-
![](https://gitee.com/tysondai/img/raw/master/20220423154450.png)
1033+
![](https://raw.githubusercontent.com/Tyson0314/img/master/20220423154450.png)
10341034

10351035

10361036

Java/Java并发面试题.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464

6565
### 线程池执行原理?
6666

67-
![线程池执行流程](https://gitee.com/tysondai/img/raw/master/线程池执行流程.png)
67+
![线程池执行流程](https://raw.githubusercontent.com/Tyson0314/img/master/线程池执行流程.png)
6868

6969
1. 当线程池里存活的线程数小于核心线程数`corePoolSize`时,这时对于一个新提交的任务,线程池会创建一个线程去处理任务。当线程池里面存活的线程数小于等于核心线程数`corePoolSize`时,线程池里面的线程会一直存活着,就算空闲时间超过了`keepAliveTime`,线程也不会被销毁,而是一直阻塞在那里一直等待任务队列的任务来执行。
7070
2. 当线程池里面存活的线程数已经等于corePoolSize了,这是对于一个新提交的任务,会被放进任务队列workQueue排队等待执行。
@@ -199,7 +199,7 @@ public static ExecutorService newCachedThreadPool() {
199199
3. 修改 `ScheduledFutureTask` 的 time 变量为下次将要被执行的时间;
200200
4. 把这个修改 time 之后的 `ScheduledFutureTask` 放回 `DelayQueue` 中(`DelayQueue.add()`)。
201201

202-
![](https://gitee.com/tysondai/img/raw/master/scheduled-task.jpg)
202+
![](https://raw.githubusercontent.com/Tyson0314/img/master/scheduled-task.jpg)
203203

204204
适用场景:周期性执行任务的场景,需要限制线程数量的场景。
205205

@@ -225,7 +225,7 @@ public static ExecutorService newCachedThreadPool() {
225225

226226
**终止(TERMINATED)**:表示该线程已经执行完毕。
227227

228-
![](https://gitee.com/tysondai/img/raw/master/image-20210909235618175.png)
228+
![](https://raw.githubusercontent.com/Tyson0314/img/master/image-20210909235618175.png)
229229

230230
> 图片来源:Java并发编程的艺术
231231
@@ -401,7 +401,7 @@ class RunnableDemo implements Runnable {
401401

402402
如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方持有的资源,所以这两个线程就会互相等待而进入死锁状态。
403403

404-
![死锁](https://gitee.com/tysondai/img/raw/master/死锁.png)
404+
![死锁](https://raw.githubusercontent.com/Tyson0314/img/master/死锁.png)
405405

406406
下面通过例子说明线程死锁,代码来自并发编程之美。
407407

@@ -686,7 +686,7 @@ class SeasonThreadTask implements Runnable{
686686

687687
每个线程都有一个`ThreadLocalMap``ThreadLocal`内部类),Map中元素的键为`ThreadLocal`,而值对应线程的变量副本。
688688

689-
![](https://gitee.com/tysondai/img/raw/master/threadlocal.png)
689+
![](https://raw.githubusercontent.com/Tyson0314/img/master/threadlocal.png)
690690

691691
调用`threadLocal.set()`-->调用`getMap(Thread)`-->返回当前线程的`ThreadLocalMap<ThreadLocal, value>`-->`map.set(this, value)`,this是`threadLocal`本身。源码如下:
692692

@@ -783,7 +783,7 @@ private volatile int state;//共享变量,使用volatile修饰保证线程可
783783

784784
同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态(独占或共享 )构造成为一个节点(Node)并将其加入同步队列并进行自旋,当同步状态释放时,会把首节点中的后继节点对应的线程唤醒,使其再次尝试获取同步状态。
785785

786-
![](https://gitee.com/tysondai/img/raw/master/aqs.png)
786+
![](https://raw.githubusercontent.com/Tyson0314/img/master/aqs.png)
787787

788788
## ReentrantLock 是如何实现可重入性的?
789789

0 commit comments

Comments
 (0)