浅析JVM模型以及java代码运行流程

在一段代码被运行启动的时候:

1.java文件被jdk编译成为后缀为.class的文件

2. .class文件会通过我们的类装载子系统 加载 到 我们的运行时数据区 

3. 通过字节码执行引擎 运行我们的.class 文件。

而 堆、栈(线程)、程序计数器、本地方法栈、方法区(元空间) 这五个从本质意义上来说 都是 内存。 没错 ,本质上都是JVM内存的一部分。

 

1.栈(线程) 本质上来说存放的就是我们的局部变量。 什么是局部变量 比如 String a = "1"; 这句代码里 你可以理解为a 就是存放在栈中; 当我的程序 比如 

 

public int car(){

  int b =1;

}

public static void main(String args[]){

  String a = "1";

}

这段代码运行的时候 我的JVM内存中 栈 这块区域 就会单独开辟一个线程栈 给这个线程使用。  

先解释一个名词                        栈桢 : 一个方法对应一个栈桢内存区域。

每一个方法都可以理解为在栈中拥有一块属于自己的栈桢空间,每一个局部变量就存在他所在的方法体分配的栈桢内。

栈还有一个特点就是先进后出。

什么是先进后出 为什么是先进后出?

我们的java程序在运行的时候 一定是先执行主方法 也就是main方法。 这个时候main方法先入栈。 先进

当main方法运行时调用子方法的时候   子方法也入栈了, 当子方法运行完毕的时候 子方法里的局部变量就会被销毁 ,也就是b会被销毁。 只有当整个程序执行完 main方法才会被销毁。这就是我们所说的 先进后出  就是这个道理

 

 而栈中其实存放了 包括 局部变量表  操作数栈 动态链接 方法出口。 

2.堆 , a存放在栈中,那么 "1" 存放的就是在堆中,  讲深一点就是 堆存放的是具体的值, 堆从物理的角度上来说 就是一个物理地址 010XX 类似这样的地址。这个地址存放的就是 "1" 这个值。 而栈存放的变量a 实际上就是你的物理地址。 

也就是  a(物理地址)   -》   1(物理地址存放1这个值)  不知道我这样说大家能不能理解。

3.方法区(元空间)  这个其实存放的是 我们的一些声明的static的常量  变量  。  尤其是变量   静态变量实例化的时候, 其实也是有一根指针指向   堆

在JDK8的版本中,方法区被移除,取而代之的是metaspace(元数据空间)。

4.程序计数器  首先我们要搞清楚JVM的多线程实现方式。JVM的多线程是通过CPU时间片轮转(即线程轮流切换并分配处理器执行时间)算法来实现的。也就是说,某个线程在执行过程中可能会因为时间片耗尽而被挂起,而另一个线程获取到时间片开始执行。当被挂起的线程重新获取到时间片的时候,它要想从被挂起的地方继续执行,就必须知道它上次执行到哪个位置,在JVM中,通过程序计数器来记录某个线程的字节码执行位置。因此,程序计数器是具备线程隔离的特性,也就是说,每个线程工作时都有属于自己的独立计数器。

5.本地方法栈  看过源代码的都知道,其实JDK最底层的实现 在linux平台使用部署 都是调用的linux的核心内核函数 linux的核心内核函数都是用C语言去实现的

当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。本地方法可以通过本地方法接口来访问虚拟机的运行时数据区,但不止如此,它还可以做任何它想做的事情。

本地方法本质上时依赖于实现的,虚拟机实现的设计者们可以自由地决定使用怎样的机制来让Java程序调用本地方法。

任何本地方法接口都会使用某种本地方法栈。当线程调用Java方法时,虚拟机会创建一个新的栈帧并压入Java栈。然而当它调用的是本地方法时,虚拟机会保持Java栈不变,不再在线程的Java栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。

 

以上文章一些内容也是本人百度的 因为我发现说的比我好得多。

 

 


    

 

 

posted @ 2021-09-28 18:43  斯拉克  阅读(62)  评论(0编辑  收藏  举报