Skip to content

Commit 74d4602

Browse files
committed
interview doc
1 parent 96e690f commit 74d4602

File tree

5 files changed

+834
-1256
lines changed

5 files changed

+834
-1256
lines changed

docs/.vuepress/dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit 2b29562a0d86402fd71e9d25f910189d1d9a2356
1+
Subproject commit 7969fe8201d8647d8bbe4c4fb6604b174efd580d

docs/interview/.DS_Store

0 Bytes
Binary file not shown.

docs/interview/JVM-FAQ.md

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ Java 虚拟机把描述类的数据从 Class 文件加载到内存,并对数
9595
9696

9797

98+
### 🎯 符号引用是什么?
99+
100+
符号引用就是 **字节码层面的抽象标识**,比如类名 `"com/example/Test"`、方法名 `"doSomething()V"`。在解析阶段,JVM 会把这些符号解析成具体的 **内存地址或偏移量**(直接引用)。
101+
102+
- 符号引用存在于:
103+
- 类的常量池
104+
- 方法符号引用
105+
- 字段符号引用
106+
107+
108+
98109
### 🎯 触发初始化的条件(主动引用)
99110

100111
以下情况会触发类的初始化阶段 :
@@ -111,7 +122,7 @@ Java 虚拟机把描述类的数据从 Class 文件加载到内存,并对数
111122

112123
- 通过子类引用父类的静态字段(仅初始化父类)。
113124
- 通过数组定义引用类(如 `ClassA[] arr = new ClassA[10]`
114-
- 访问类的 `final static` 常量(已在准备阶段赋值
125+
- 访问类的 `final static` 常量(编译期已放入常量池
115126

116127
### 🎯 类卸载条件
117128

@@ -263,10 +274,6 @@ Java 虚拟机对 class 文件采用的是**按需加载**的方式,也就是
263274
264275
双亲委派
265276
266-
267-
268-
### 🎯 在多线程的情况下,类的加载为什么不会出现重复加载的情况?
269-
270277
**三个类加载器的关系,不是父子关系,是组合关系。**
271278
272279
看看类加载器的加载类的方法 loadClass
@@ -404,13 +411,13 @@ protected Class<?> loadClass(String name, boolean resolve)
404411
> ├─────────────────────────────────────────────────────────────┤
405412
> │ 线程共享区域 │
406413
> │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
407-
> │ │ 方法区(Method) │ │ 堆内存(Heap) │ │ 直接内存 │ │
408-
> │ │ (元空间) │ │ │ │ (Direct) │ │
414+
> │ │ 方法区(Method) │ │ 堆内存(Heap) │ │ 直接内存 │ │
415+
> │ │ (元空间) │ │ │ │ (Direct) │ │
409416
> │ └─────────────────┘ └─────────────────┘ └─────────────┘ │
410417
> ├─────────────────────────────────────────────────────────────┤
411418
> │ 线程私有区域 │
412419
> │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
413-
> │ │ 程序计数器(PC) │ │ 虚拟机栈(Stack) │ │ 本地方法栈 │ │
420+
> │ │ 程序计数器(PC) │ │ 虚拟机栈(Stack) │ │ 本地方法栈 │ │
414421
> │ │ │ │ │ │ (Native) │ │
415422
> │ └─────────────────┘ └─────────────────┘ └─────────────┘ │
416423
> └─────────────────────────────────────────────────────────────┘
@@ -574,6 +581,24 @@ protected Class<?> loadClass(String name, boolean resolve)
574581
575582
576583
584+
### 🎯 栈帧的内部结构?
585+
586+
在 Java 中,**虚拟机栈**(JVM Stack)是 JVM 内存模型的一个重要组成部分,它用于存储方法调用的相关信息,如局部变量、操作数栈、方法调用的返回地址等。每个线程在执行时都会有一个独立的虚拟机栈,确保多线程间的数据隔离。
587+
588+
- **每个线程都有自己的虚拟机栈**,栈是按照方法调用来组织的。
589+
- 栈中的数据是 **方法调用栈帧**(Stack Frame),每个栈帧表示一个方法的执行。
590+
- 方法在执行时,JVM 会为每个方法分配一个栈帧,每当方法调用时会将栈帧压入栈中,方法返回时会将栈帧弹出。
591+
592+
每个**栈帧**(Stack Frame)中存储着:
593+
594+
- 局部变量表(Local Variables)
595+
- 操作数栈(Operand Stack)(或称为表达式栈)
596+
- 动态链接(Dynamic Linking):指向运行时常量池的方法引用
597+
- 方法返回地址(Return Address):方法正常退出或异常退出的地址
598+
- 一些附加信息
599+
600+
![图片](https://mmbiz.qpic.cn/mmbiz_jpg/Z0fxkgAKKLMAVEVNlW7gDqZIFzSvVq29fMr12sicgr3HIgRFtFRY8IAcDvwP6orNRRIojrn3edcS3h2ibblgAgQg/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)
601+
577602
### 🎯 Java 对象是不是都创建在堆上的呢?
578603
579604
> JVM 的一些高级优化技术,例如逃逸分析(Escape Analysis),可以使对象在栈上分配内存,而不是堆上。逃逸分析可以判断对象的作用域,如果确定对象不会逃逸出方法(即对象仅在方法内部使用),JVM 可以选择将对象分配在栈上。这种优化减少了垃圾回收的负担,并提高了性能。
@@ -583,11 +608,10 @@ protected Class<?> loadClass(String name, boolean resolve)
583608
在 Java 中,并不是所有对象都严格创建在堆上,尽管大部分情况下确实如此。具体来说:
584609
585610
1. **普通对象:通常创建在堆上**
586-
587611
- Java 中通过 `new` 关键字创建的对象(比如 `new MyClass()`),以及通过反射、序列化等机制创建的对象,默认分配在堆上。
588-
612+
589613
- 堆是 JVM 中用来存储对象实例和数组的区域,所有线程共享。
590-
614+
591615
2. 栈上分配对象(逃逸分析 & 标量替换优化)
592616
- 在某些情况下,JVM 可以通过优化技术将原本应该在堆上分配的对象转移到栈上分配。这种优化是通过**逃逸分析(Escape Analysis)**实现的。
593617
- 如果 JVM 确定某个对象不会在当前方法之外被访问(不会逃逸当前线程),那么它可能会将该对象分配在栈上。
@@ -822,26 +846,6 @@ OOM 如果通俗点儿说,就是 JVM 内存不够用了,javadoc 中对[OutOf
822846

823847

824848

825-
### 🎯 栈帧的内部结构?
826-
827-
Java 中,**虚拟机栈**JVM Stack)是 JVM 内存模型的一个重要组成部分,它用于存储方法调用的相关信息,如局部变量、操作数栈、方法调用的返回地址等。每个线程在执行时都会有一个独立的虚拟机栈,确保多线程间的数据隔离。
828-
829-
- **每个线程都有自己的虚拟机栈**,栈是按照方法调用来组织的。
830-
- 栈中的数据是 **方法调用栈帧**Stack Frame),每个栈帧表示一个方法的执行。
831-
- 方法在执行时,JVM 会为每个方法分配一个栈帧,每当方法调用时会将栈帧压入栈中,方法返回时会将栈帧弹出。
832-
833-
每个**栈帧**Stack Frame)中存储着:
834-
835-
- 局部变量表(Local Variables
836-
- 操作数栈(Operand Stack)(或称为表达式栈)
837-
- 动态链接(Dynamic Linking):指向运行时常量池的方法引用
838-
- 方法返回地址(Return Address):方法正常退出或异常退出的地址
839-
- 一些附加信息
840-
841-
![图片](https://mmbiz.qpic.cn/mmbiz_jpg/Z0fxkgAKKLMAVEVNlW7gDqZIFzSvVq29fMr12sicgr3HIgRFtFRY8IAcDvwP6orNRRIojrn3edcS3h2ibblgAgQg/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)
842-
843-
844-
845849
### 🎯 什么情况下会发生栈内存溢出?
846850

847851
- 栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用类型

0 commit comments

Comments
 (0)