@@ -95,6 +95,17 @@ Java 虚拟机把描述类的数据从 Class 文件加载到内存,并对数
95
95
96
96
97
97
98
+ ### 🎯 符号引用是什么?
99
+
100
+ 符号引用就是 ** 字节码层面的抽象标识** ,比如类名 ` "com/example/Test" ` 、方法名 ` "doSomething()V" ` 。在解析阶段,JVM 会把这些符号解析成具体的 ** 内存地址或偏移量** (直接引用)。
101
+
102
+ - 符号引用存在于:
103
+ - 类的常量池
104
+ - 方法符号引用
105
+ - 字段符号引用
106
+
107
+
108
+
98
109
### 🎯 触发初始化的条件(主动引用)
99
110
100
111
以下情况会触发类的初始化阶段 :
@@ -111,7 +122,7 @@ Java 虚拟机把描述类的数据从 Class 文件加载到内存,并对数
111
122
112
123
- 通过子类引用父类的静态字段(仅初始化父类)。
113
124
- 通过数组定义引用类(如 ` ClassA[] arr = new ClassA[10] ` )
114
- - 访问类的 ` final static ` 常量(已在准备阶段赋值 )
125
+ - 访问类的 ` final static ` 常量(编译期已放入常量池 )
115
126
116
127
### 🎯 类卸载条件
117
128
@@ -263,10 +274,6 @@ Java 虚拟机对 class 文件采用的是**按需加载**的方式,也就是
263
274
264
275
双亲委派
265
276
266
-
267
-
268
- ### 🎯 在多线程的情况下,类的加载为什么不会出现重复加载的情况?
269
-
270
277
** 三个类加载器的关系,不是父子关系,是组合关系。**
271
278
272
279
看看类加载器的加载类的方法 loadClass
@@ -404,13 +411,13 @@ protected Class<?> loadClass(String name, boolean resolve)
404
411
> ├─────────────────────────────────────────────────────────────┤
405
412
> │ 线程共享区域 │
406
413
> │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
407
- > │ │ 方法区(Method) │ │ 堆内存(Heap) │ │ 直接内存 │ │
408
- > │ │ (元空间) │ │ │ │ (Direct) │ │
414
+ > │ │ 方法区(Method) │ │ 堆内存(Heap) │ │ 直接内存 │ │
415
+ > │ │ (元空间) │ │ │ │ (Direct) │ │
409
416
> │ └─────────────────┘ └─────────────────┘ └─────────────┘ │
410
417
> ├─────────────────────────────────────────────────────────────┤
411
418
> │ 线程私有区域 │
412
419
> │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
413
- > │ │ 程序计数器(PC) │ │ 虚拟机栈(Stack) │ │ 本地方法栈 │ │
420
+ > │ │ 程序计数器(PC) │ │ 虚拟机栈(Stack) │ │ 本地方法栈 │ │
414
421
> │ │ │ │ │ │ (Native) │ │
415
422
> │ └─────────────────┘ └─────────────────┘ └─────────────┘ │
416
423
> └─────────────────────────────────────────────────────────────┘
@@ -574,6 +581,24 @@ protected Class<?> loadClass(String name, boolean resolve)
574
581
575
582
576
583
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
+ 
601
+
577
602
### 🎯 Java 对象是不是都创建在堆上的呢?
578
603
579
604
> JVM 的一些高级优化技术,例如逃逸分析(Escape Analysis),可以使对象在栈上分配内存,而不是堆上。逃逸分析可以判断对象的作用域,如果确定对象不会逃逸出方法(即对象仅在方法内部使用),JVM 可以选择将对象分配在栈上。这种优化减少了垃圾回收的负担,并提高了性能。
@@ -583,11 +608,10 @@ protected Class<?> loadClass(String name, boolean resolve)
583
608
在 Java 中,并不是所有对象都严格创建在堆上,尽管大部分情况下确实如此。具体来说:
584
609
585
610
1. **普通对象:通常创建在堆上**
586
-
587
611
- Java 中通过 `new` 关键字创建的对象(比如 `new MyClass()`),以及通过反射、序列化等机制创建的对象,默认分配在堆上。
588
-
612
+
589
613
- 堆是 JVM 中用来存储对象实例和数组的区域,所有线程共享。
590
-
614
+
591
615
2. 栈上分配对象(逃逸分析 & 标量替换优化)
592
616
- 在某些情况下,JVM 可以通过优化技术将原本应该在堆上分配的对象转移到栈上分配。这种优化是通过**逃逸分析(Escape Analysis)**实现的。
593
617
- 如果 JVM 确定某个对象不会在当前方法之外被访问(不会逃逸当前线程),那么它可能会将该对象分配在栈上。
@@ -822,26 +846,6 @@ OOM 如果通俗点儿说,就是 JVM 内存不够用了,javadoc 中对[OutOf
822
846
823
847
824
848
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
-
845
849
### 🎯 什么情况下会发生栈内存溢出?
846
850
847
851
- 栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用类型
0 commit comments