Skip to content

Commit da6295e

Browse files
committed
整理JVM面试题
1 parent c1f015c commit da6295e

File tree

1 file changed

+54
-69
lines changed

1 file changed

+54
-69
lines changed

Java/JVM高频面试题.md

Lines changed: 54 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@
2323
- [可作为GC Roots的对象有哪些?](#%E5%8F%AF%E4%BD%9C%E4%B8%BAgc-roots%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%9C%89%E5%93%AA%E4%BA%9B)
2424
- [什么情况下类会被卸载?](#%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E4%B8%8B%E7%B1%BB%E4%BC%9A%E8%A2%AB%E5%8D%B8%E8%BD%BD)
2525
- [强引用、软引用、弱引用、虚引用是什么,有什么区别?](#%E5%BC%BA%E5%BC%95%E7%94%A8%E8%BD%AF%E5%BC%95%E7%94%A8%E5%BC%B1%E5%BC%95%E7%94%A8%E8%99%9A%E5%BC%95%E7%94%A8%E6%98%AF%E4%BB%80%E4%B9%88%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB)
26+
- [GC是什么?为什么要GC?](#gc%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81gc)
2627
- [Minor GC 和 Full GC的区别?](#minor-gc-%E5%92%8C-full-gc%E7%9A%84%E5%8C%BA%E5%88%AB)
2728
- [内存的分配策略?](#%E5%86%85%E5%AD%98%E7%9A%84%E5%88%86%E9%85%8D%E7%AD%96%E7%95%A5)
2829
- [Full GC 的触发条件?](#full-gc-%E7%9A%84%E8%A7%A6%E5%8F%91%E6%9D%A1%E4%BB%B6)
2930
- [垃圾回收算法有哪些?](#%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%9C%89%E5%93%AA%E4%BA%9B)
3031
- [有哪些垃圾回收器?](#%E6%9C%89%E5%93%AA%E4%BA%9B%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E5%99%A8)
3132
- [常用的 JVM 调优的命令都有哪些?](#%E5%B8%B8%E7%94%A8%E7%9A%84-jvm-%E8%B0%83%E4%BC%98%E7%9A%84%E5%91%BD%E4%BB%A4%E9%83%BD%E6%9C%89%E5%93%AA%E4%BA%9B)
3233
- [对象头了解吗?](#%E5%AF%B9%E8%B1%A1%E5%A4%B4%E4%BA%86%E8%A7%A3%E5%90%97)
34+
- [main方法执行过程](#main%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B)
35+
- [对象创建过程](#%E5%AF%B9%E8%B1%A1%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B)
3336
- [如何排查 OOM 的问题?](#%E5%A6%82%E4%BD%95%E6%8E%92%E6%9F%A5-oom-%E7%9A%84%E9%97%AE%E9%A2%98)
34-
- [GC是什么?为什么要GC?](#gc%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81gc)
3537

3638
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
3739

@@ -115,19 +117,11 @@ JDK 1.8 的时候,`HotSpot`的永久代被彻底移除了,使用元空间替
115117

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

118-
![](https://gitee.com/tysondai/img/raw/master/string-new.png)
119-
120-
![](https://gitee.com/tysondai/img/raw/master/string-intern.png)
121-
122-
![](https://gitee.com/tysondai/img/raw/master/string-equal.png)
123-
124-
> 图片来源:https://blog.csdn.net/soonfly
125-
126120
### 直接内存
127121

128-
直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致 OutOfMemoryError 错误出现。
122+
直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致 `OutOfMemoryError` 错误出现。
129123

130-
NIO的Buffer提供了DirectBuffer,可以直接访问系统物理内存,避免堆内内存到堆外内存的数据拷贝操作,提高效率。DirectBuffer直接分配在物理内存中,并不占用堆空间,其可申请的最大内存受操作系统限制,不受最大堆内存的限制。
124+
NIO的Buffer提供了`DirectBuffer`,可以直接访问系统物理内存,避免堆内内存到堆外内存的数据拷贝操作,提高效率。`DirectBuffer`直接分配在物理内存中,并不占用堆空间,其可申请的最大内存受操作系统限制,不受最大堆内存的限制。
131125

132126
直接内存的读写操作比堆内存快,可以提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到直接内存。
133127

@@ -357,6 +351,10 @@ WeakReference<String> weakRef = new WeakReference<String>(str);
357351

358352
**虚引用**:虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。**虚引用主要是为了能在对象被收集器回收时收到一个系统通知**
359353

354+
## GC是什么?为什么要GC?
355+
356+
GC,`Gabage Collection`,即垃圾收集。内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序的不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
357+
360358
## Minor GC 和 Full GC的区别?
361359

362360
- **Minor GC**:回收新生代,因为新生代对象存活时间很短,因此 `Minor GC`会频繁执行,执行的速度一般也会比较快。
@@ -395,15 +393,15 @@ WeakReference<String> weakRef = new WeakReference<String>(str);
395393

396394
**老年代空间不足**
397395

398-
老年代空间不足的常见场景为前文所讲的大对象直接进入老年代、长期存活的对象进入老年代等。为了避免以上原因引起的 Full GC,应当尽量不要创建过大的对象以及数组。除此之外,可以通过 -Xmn 参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代。还可以通过 -XX:MaxTenuringThreshold 调大对象进入老年代的年龄,让对象在新生代多存活一段时间。
396+
老年代空间不足的常见场景为前文所讲的大对象直接进入老年代、长期存活的对象进入老年代等。为了避免以上原因引起的 Full GC,应当尽量不要创建过大的对象以及数组。除此之外,可以通过 `-Xmn` 参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代。还可以通过 `-XX:MaxTenuringThreshold` 调大对象进入老年代的年龄,让对象在新生代多存活一段时间。
399397

400398
**空间分配担保失败**
401399

402400
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。
403401

404402
**JDK 1.7 及以前的永久代空间不足**
405403

406-
在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 Class 的信息、常量、静态变量等数据。当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么虚拟机会抛出 java.lang.OutOfMemoryError。
404+
在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 Class 的信息、常量、静态变量等数据。当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么虚拟机会抛出 `java.lang.OutOfMemoryError`
407405

408406

409407

@@ -690,49 +688,49 @@ Java 内存中的对象由以下三部分组成:**对象头**、**实例数据
690688
**内存对齐的主要作用是:**
691689

692690
1. 平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
693-
2. 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。
694-
695-
1. ## main方法执行过程
696-
697-
以下是示例代码:
698-
699-
```java
700-
public class Application {
701-
public static void main(String[] args) {
702-
Person p = new Person("大彬");
703-
p.getName();
704-
}
705-
}
706-
707-
class Person {
708-
public String name;
709-
710-
public Person(String name) {
711-
this.name = name;
712-
}
713-
714-
public String getName() {
715-
return this.name;
716-
}
717-
}
718-
```
719-
720-
执行`main`方法的过程如下:
721-
722-
1. 编译`Application.java`后得到 `Application.class` 后,执行这个`class`文件,系统会启动一个 `JVM` 进程,从类路径中找到一个名为 `Application.class` 的二进制文件,将 `Application` 类信息加载到运行时数据区的方法区内,这个过程叫做类的加载。
723-
2. JVM 找到 `Application` 的主程序入口,执行`main`方法。
724-
3. `main`方法的第一条语句为 `Person p = new Person("大彬") `,就是让 JVM 创建一个`Person`对象,但是这个时候方法区中是没有 `Person` 类的信息的,所以 JVM 马上加载 `Person` 类,把 `Person` 类的信息放到方法区中。
725-
4. 加载完 `Person` 类后,JVM 在堆中分配内存给 `Person` 对象,然后调用构造函数初始化 `Person` 对象,这个 `Person` 对象持有**指向方法区中的 Person 类的类型信息**的引用。
726-
5. 执行`p.getName()`时,JVM 根据 p 的引用找到 p 所指向的对象,然后根据此对象持有的引用定位到方法区中 `Person` 类的类型信息的方法表,获得 `getName()` 的字节码地址。
727-
6. 执行`getName()`方法。
728-
729-
1. ## 对象创建过程
730-
731-
1. **类加载检查**:当虚拟机遇到一条 `new` 指令时,首先检查是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那先执行类加载。
732-
2. **分配内存**:在类加载检查通过后,接下来虚拟机将为对象实例分配内存。
733-
3. **初始化**。分配到的内存空间都初始化为零值,通过这个操作保证了对象的字段可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
734-
4. **设置对象头**`Hotspot` 虚拟机的对象头包括:存储对象自身的运行时数据(哈希码、分代年龄、锁标志等等)、类型指针和数据长度(数组对象才有),类型指针就是对象指向它的类信息的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
735-
5. **按照`Java`代码进行初始化**
691+
2. 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。
692+
693+
## main方法执行过程
694+
695+
以下是示例代码:
696+
697+
```java
698+
public class Application {
699+
public static void main(String[] args) {
700+
Person p = new Person("大彬");
701+
p.getName();
702+
}
703+
}
704+
705+
class Person {
706+
public String name;
707+
708+
public Person(String name) {
709+
this.name = name;
710+
}
711+
712+
public String getName() {
713+
return this.name;
714+
}
715+
}
716+
```
717+
718+
执行`main`方法的过程如下:
719+
720+
1. 编译`Application.java`后得到 `Application.class` 后,执行这个`class`文件,系统会启动一个 `JVM` 进程,从类路径中找到一个名为 `Application.class` 的二进制文件,将 `Application` 类信息加载到运行时数据区的方法区内,这个过程叫做类的加载。
721+
2. JVM 找到 `Application` 的主程序入口,执行`main`方法。
722+
3. `main`方法的第一条语句为 `Person p = new Person("大彬") `,就是让 JVM 创建一个`Person`对象,但是这个时候方法区中是没有 `Person` 类的信息的,所以 JVM 马上加载 `Person` 类,把 `Person` 类的信息放到方法区中。
723+
4. 加载完 `Person` 类后,JVM 在堆中分配内存给 `Person` 对象,然后调用构造函数初始化 `Person` 对象,这个 `Person` 对象持有**指向方法区中的 Person 类的类型信息**的引用。
724+
5. 执行`p.getName()`时,JVM 根据 p 的引用找到 p 所指向的对象,然后根据此对象持有的引用定位到方法区中 `Person` 类的类型信息的方法表,获得 `getName()` 的字节码地址。
725+
6. 执行`getName()`方法。
726+
727+
## 对象创建过程
728+
729+
1. **类加载检查**:当虚拟机遇到一条 `new` 指令时,首先检查是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那先执行类加载。
730+
2. **分配内存**:在类加载检查通过后,接下来虚拟机将为对象实例分配内存。
731+
3. **初始化**。分配到的内存空间都初始化为零值,通过这个操作保证了对象的字段可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
732+
4. **设置对象头**`Hotspot` 虚拟机的对象头包括:存储对象自身的运行时数据(哈希码、分代年龄、锁标志等等)、类型指针和数据长度(数组对象才有),类型指针就是对象指向它的类信息的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
733+
5. **按照`Java`代码进行初始化**
736734

737735
## 如何排查 OOM 的问题?
738736

@@ -742,22 +740,9 @@ Java 内存中的对象由以下三部分组成:**对象头**、**实例数据
742740
- jstat 查看监控 JVM 的内存和 GC 情况,评估问题大概出在什么区域;
743741
- 使用 MAT 工具载入 dump 文件,分析大对象的占用情况 。
744742

745-
## GC是什么?为什么要GC?
746-
747-
GC 是垃圾收集的意思(Gabage Collection)。内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序的不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
748-
749743

750744

751745
**参考资料**
752746

753747
- 周志明. 深入理解 Java 虚拟机 [M]. 机械工业出版社
754748

755-
756-
757-
> 本文已经收录到github仓库,此仓库用于分享Java相关知识总结,包括Java基础、MySQL、Spring Boot、MyBatis、Redis、RabbitMQ、计算机网络、数据结构与算法等等,欢迎大家提pr和star!
758-
>
759-
> github地址:https://github.com/Tyson0314/Java-learning
760-
>
761-
> 如果github访问不了,可以访问gitee仓库。
762-
>
763-
> gitee地址:https://gitee.com/tysondai/Java-learning

0 commit comments

Comments
 (0)