前言

本文将具体解说JVM整体的构造,以及各个构造的里的具体形成与作用


一、JVM是什么?

JVM百度百科介绍 简略来说JAVA是运行在JVM下面的,没有JVM那么JAVA文件是无奈运行的

二、JVM组成构造

  1. 办法区
  2. 本地办法栈
  3. 程序计数器

**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 复制代码

栈帧构造组成

  1. 局部变量表:次要用来保留申明的局部变量以及办法的参数信息,局部变量表作用于为以后办法,当办法执行实现后,局部变量表也会随之删除,开释内存。另外局部变量表里用来保存信息的叫做变量槽(slot)

  1. 操作数栈:顾名思义,操作数栈其本质就是个栈,压栈,出栈两个操作,例如执行a+b,先将局部变量表中的a与b别离压入栈中,接着执行加法操作,最终出栈。
  2. 动静链接:是在程序运行期间实现的将符号援用替换为间接援用叫动静链接,既然有动静链接那么天然也有动态链接,局部符号援用在类加载阶段(解析)的时候就转化为间接援用,这种转化为动态链接。
  3. 办法返回地址:在办法退出(失常执行/异样返回)后,返回办法被调用的地位。

**栈帧结构图**

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)

总结

  1. 运行时数据区次要由程序计数器办法区本地办法栈
  2. 线程栈、程序计数器、本地办法栈都是线程公有的区域,堆、办法区是线程共享的区域。
  3. 堆分为细分为Eden、From、To、老年代
  4. 对象不全都是在堆中,没有产生逃逸的对象在栈中。

参考:《2020最新Java根底精讲视频教程和学习路线!》

链接:https://juejin.cn/post/692200...