住房和城乡建设部网站施工员,页面设计上边距在哪里找,云南信息发布平台,公司网站怎样实名认证概述 很多人想要到阿里巴巴、美团、京东等互联网大公司去面试#xff0c;但是现在互联网大厂面试一般都必定会考核JVM相关的知识积累和实践经验#xff0c;毕竟线上系统写好代码部署之后#xff0c;每个工程师都必须关注JVM相关的东西#xff0c;比如OOM、GC等问题. 所以一… 概述 很多人想要到阿里巴巴、美团、京东等互联网大公司去面试但是现在互联网大厂面试一般都必定会考核JVM相关的知识积累和实践经验毕竟线上系统写好代码部署之后每个工程师都必须关注JVM相关的东西比如OOM、GC等问题. 所以一起来看看JVM的最基本的区域划分以及工作原理这个基本上是互联网公司面试必问。 区域划分 jvm的区域划分如下所示 大致就是分为程序计数器虚拟机栈堆方法区本地方法栈这几个部分。 接下来我们从自己写好的Java代码如何通过JVM来运行的角度来分析一下JVM里这些区域是如何支撑我们的Java代码跑起来的。 程序计数器 假设我们有如下的一个类就是最最基本的一个HelloWorld而已 public class HelloWorld {public static void main(String[] args) {System.out.println(Hello World);}} 上面那段代码首先会存在于 “.java” 后缀的文件里这个文件就是java源代码文件但是这个文件是面向我们程序员的计算机他是看不懂你写的这段代码的 所以此时就得通过编译器把“.java”后缀的源代码文件编译为“.class”后缀的字节码文件。 这个“.class”后缀的字节码文件里存放的就是对你写出来的代码编译好的字节码了这个字节码才是计算器可以理解的一种语言而不是我们写出来的那一堆代码。 这个字节码看起来大概是下面这样的 这段字节码并不是完全对照着HelloWorld那个类来写的就是给一段示例让大家知道“.java”翻译成的“.class”是大概什么样子的。 这里比如说“0: aload_0”这样的就是“字节码指令”他对应了一条一条的机器指令计算机只有读到这种机器码指令才知道具体应该要干什么。 比如说字节码指令可能会让计算机从内存里读取某个数据或者把某个数据写入到内存里去都有可能各种各样的指令就会指示计算机去干各种各样的事情。 所以现在首先明白一点我们写好的Java代码是会被翻译成字节码的对应各种字节码指令。 那么Java代码通过JVM跑起来的第一件事情就明确了 首先Java代码被编译出来的字节码指令一定会被一条一条的执行这样才能实现我们写好的代码被执行的效果。 那么在执行字节码指令的时候JVM里的程序计数器就是用来记录每个线程当前执行的字节码指令的位置的记录当前线程目前执行到了哪一条字节码指令。 因为会有多个线程来并发的执行各种不同的代码所以每个线程都有自己的一个程序计数器专门记录当前这个线程目前执行到了哪一条字节码指令了 下图更加清晰的展示出了他们之间的关系。 Java虚拟机栈 Java代码在执行的时候一定是线程来执行某个方法中的代码比如哪怕就是上面的那个最基础的HelloWorld代码也会有一个main线程来执行main方法里的代码。 在方法里经常会定义一些方法内的局部变量比如下面这样就在方法里定义了一个局部变量“name”。 public void sayHello() {String name hello;} 所以JVM必须有一块区域是来保存每个方法内的局部变量等等数据的这个区域就是Java虚拟机栈 每个线程都会去执行各种方法的代码方法内还会嵌套调用其他的方法所以首先每个线程都有自己的Java虚拟机栈。 如果线程执行了一个方法那么就会被这个方法调用创建对应的一个栈帧栈帧里就有这个方法的局部变量表 、操作数栈、动态链接、方法出口等东西但是这里别的不太好理解先理解一个局部变量就可以。 比如说一个线程调用了上面写的“sayHello”方法那么就会为“sayHello”方法创建一个栈帧压入线程自己的Java虚拟机栈里面去。 在栈帧的局部变量表里就会有“name”这个局部变量下图展示了这个过程。 接着如果“sayHello”方法调用了另外一个“greeting”方法 比如下面那样的代码 那么这个时候会给“greeting”方法又创建一个栈帧压入线程的Java虚拟机栈里因为开始执行“greeting”方法了而且“greeting”方法的栈帧的局部变量表里会有一个“greet”变量这是“greeting”方法的局部变量。 接着如果“greeting”方法执行完毕了就会把“greeting”方法对应的栈帧从Java虚拟机栈里给出栈然后如果“sayHello”方法也执行完毕了就会把“sayHello”方法也从Java虚拟机栈里出栈。 这就是JVM中的 “ Java虚拟机栈 ” 这个组件的作用调用执行任何方法的时候都会给方法创建栈帧然后入栈。 而在栈帧里存放了这个方法对应的局部变量之类的数据包括这个方法执行的其他相关的信息方法执行完毕之后就出栈。 Java堆内存 JVM中有另外一个非常关键的区域就是Java堆这里就是存放我们在代码中创建的各种对象的比如说下面的代码 public void teach(String name) {Student student new Student(name);student.study();} 上面的 “new Student(name)” 这个代码就是创建了一个Student类型的对象实例这个对象实例里面会包含一些数据。 比如说这个Student的“name”就是属于这个对象实例的一个数据那么类似Student这样的对象就会存放在Java堆内存里。 Java堆内存区域里会放入类似Student的对象然后方法的栈帧的局部变量表里这个引用类型的“student”局部变量就会存放Student对象的地址。 相当于你可以认为局部变量表里的“student”指向了Java堆里的Student对象。 看下图会更加清晰一些。 方法区 / Metaspace 这个方法区是在JDK 1.8以前的版本里代表JVM中的一块区域主要是放类似Student类自己的信息的平时用到的各种类的信息都是放在这个区域里的还会有一些类似常量池的东西放在这个区域里。 但是在JDK 1.8以后这块区域的名字改了叫做“Metaspace”可以认为是“元数据空间”这样的意思这里当然主要其实还是存放我们自己写的各种类相关的信息。 本地方法栈 其实在JDK很多底层API里比如IO相关的NIO相关的网络Socket相关的如果大家去看他内部的源码会发现很多地方都不是Java代码了。 很多地方都会去走native方法去调用本地操作系统里面的一些方法可能调用的都是c语言写的方法或者一些底层类库比如下面这样的 public native int hashCode(); 在调用这种native方法的时候就会有线程对应的本地方法栈这个里面也是跟Java虚拟机栈类似的也是存放各种native方法的局部变量表之类的信息。 堆外内存 还有一个区域是不属于JVM的通过NIO中的allocateDirect这种API可以在Java堆外分配内存空间。 然后通过Java虚拟机里的 DirectByteBuffer 来引用和操作堆外内存空间其实很多技术都会用这种方式因为有一些场景下堆外内存分配可以提升性能。 总结 最后做一点总结我们的Java代码通过JVM来运行的时候首先一定会一行一行执行编译好的字节码指令。 然后在执行的过程中对于方法的调用会通过Java虚拟机栈来为每个方法创建栈帧入栈和出栈而且栈帧里有方法的局部变量表 接着对于对象的创建会分配到Java堆内存里去 对于类信息的存储会放在方法区 / Metaspace这样的区域里。 另外有两块特殊的区域 本地方法栈是执行native方法时候用的栈跟Java虚拟机栈是类似的 堆外内存是可以在Java堆外分配内存空间来存储一些对象。 转载 原子弹大侠阿里P8高级技术专家 经历过每日百亿流量的互联网系统架构尤其对上亿用户场景下的高并发系统架构设计以及性能优化相关领域有深入的研究。转载于:https://www.cnblogs.com/technologykai/articles/10869206.html