共计 1933 个字符,预计需要花费 5 分钟才能阅读完成。
前言
本文将具体解说 JVM 整体的构造,以及各个构造的里的具体形成与作用
一、JVM 是什么?
JVM 百度百科介绍 简略来说 JAVA 是运行在 JVM 下面的,没有 JVM 那么 JAVA 文件是无奈运行的
二、JVM 组成构造
- 栈
- 堆
- 办法区
- 本地办法栈
- 程序计数器
**JVM 结构图:**
三、JVM 构造详解
- 栈
栈是 JVM 重要的组成部分,每有一个新的线程都 JVM 都会为其在栈上调配一份内存,线程里有栈帧,程序计数器。另外线程栈内存大小决定的线程数量的多少,当线程栈内存大小设置的越大,则同时存在的线程数量越少,反则越大。另外在栈中最容易产生的谬误是StackOverflowError 栈溢出,看以下代码:
public class StackOverflowTest {
static int count = 0;
static void redo() {
count++;
redo();}
public static void main(String[] args) {
try {redo();
} catch (Throwable t) {t.printStackTrace();
System.out.println(count);
}
}
}
运行后果:java.lang.StackOverflowError
复制代码
栈帧构造组成
- 局部变量表: 次要用来保留申明的局部变量以及办法的参数信息, 局部变量表作用于为以后办法,当办法执行实现后,局部变量表也会随之删除,开释内存。另外局部变量表里用来保存信息的叫做变量槽(slot)
- 操作数栈:顾名思义,操作数栈其本质就是个栈,压栈,出栈两个操作,例如执行 a +b,先将局部变量表中的 a 与 b 别离压入栈中,接着执行加法操作,最终出栈。
- 动静链接: 是在程序运行期间实现的将符号援用替换为间接援用叫动静链接,既然有动静链接那么天然也有动态链接,局部符号援用在类加载阶段 (解析) 的时候就转化为间接援用, 这种转化为动态链接。
- 办法返回地址: 在办法退出 (失常执行 / 异样返回) 后,返回办法被调用的地位。
** 栈帧结构图 **
2. 程序计数器
程序计数器是 JVM 十分重要的一个构造,是线程公有的,每个线程独有一份,它用来保留指向下一条将被执行指令的地址,例如当线程被阻塞再进行唤醒时,从程序计数器读取指令的地址,从而继续执行。
3. 本地办法栈
本地办法栈次要是为了执行 native 办法,保留 native 办法进入区域的地址,所以本地办法栈也是线程公有的内存区域。
4. 办法区
被所有的线程共享。办法区蕴含所有的 class 和 static 变量,类的办法代码,变量名,办法名,拜访权限,返回值等等都是在办法区的。
- 堆
堆是十分重要的一个区域,治理着简直所有的对象,咱们常说的垃圾回收的次要区域就是产生在这个区域。堆分为新生代 (young) 与老年代(Old),新生代又分为 Eden 与 survivor 区,survivor 分为 From 区与 To 区。这几个区寄存着 java 的对象,当区内存不够的时候会产生 GC,GC 次要分为两种,一种是 minorGC(Young GC),另一种是 Full GC,JVM 调优次要就是缩小 Full GC 的次数。
逃逸剖析
首先大家听得最多的就是 new 进去对象是寄存在堆中的,然而在上文中,所写的是简直对象是存在堆中,那么为什么是简直呢,因为有的对象是寄存在栈中的,是不是很不堪设想,接下来来看下一段代码。
// 办法一
public Person test1() {Person person = new Person();
person.setId(1);
return person;
}
// 办法二
public void test2() {User person = new person();
person.setId(1);
}
复制代码
上述代码中很显然 test1 办法中的 personr 对象被返回了,那么这个对象就可能被其余办法进行援用,test2 办法中的 personr 对象,当办法完结的时候,该对象就是一个有效对象了,不会在其余中央被进行援用,对于这样的对象,JVM 将其调配的栈内存里,让其在办法完结时追随栈内存一起被回收掉,缩小堆内存的回收。JVM 对于这种状况能够通过开启逃逸剖析参数 (-XX:+DoEscapeAnalysis) 来优化对象内存调配地位,JDK7 之后默认开启逃逸剖析,如果要 敞开应用参数(-XX:-DoEscapeAnalysis)
总结
- 运行时数据区次要由 堆、栈 、 程序计数器 、 办法区 、 本地办法栈
- 线程栈、程序计数器、本地办法栈都是线程公有的区域,堆、办法区是线程共享的区域。
- 堆分为细分为 Eden、From、To、老年代
- 对象不全都是在堆中,没有产生逃逸的对象在栈中。
参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://juejin.cn/post/692200…