目录
前言
先看图再解释
我理解的JVM由来,以及其结构的由来:
java区别于C和C++就在于,java是跨平台的,Java砍掉指针概念,java程序员不用手动释放内存。因此我们必须自己向操作系统申请一块内存,让JVM对其进行管理,这就是运行时数据区。这样就好像把java限制在一个小房子里面,相比C很安全,比如,java的内存溢出不容易使机器宕机,再比如C语言中大小为n的数组,我们访问下标为n以上的是不会报错的,java会报错下标越界。并且java语言编译之后是不可以直接生成二进制的可执行文件,C和C++编译后的可执行文件是耦合平台的。因此java编译必须先生成一个中间产物,即class文件。存在class文件的原因就在于:
- 1、java不可直接生成二进制可执行文件。
- 2、java执行中依赖的指令集架构是基于栈的指令集架构。程序在运行时是依赖对于栈的操作的。就好比我们在科学计算器中输入一串式子:(((1+2)*(2+3)+4*5)*3让计算器计算。计算器需要对这串的每个操作和数字进行分析,遇到优先级低的操作符时需要将数字入栈,遇到操作符优先级高的则取栈顶元素计算,然后计算结果入栈。java的基于栈的指令集架构就类似于科学计算器算法。就是出栈运算,结果入栈。但是对于这串式子的解析和判断优先级是要耗时的,所以我们可以直接将其编译,生成那些对栈的操作指令,这样在实际运行的时候便快一点。java也是如此,直接将java文件交给JVM运行,需要对其进行语法词法分析,这是相当耗时的。
- 3、java不仅是跨平台的语言,并且JVM是一个跨语言的平台,其他自开发语言都可以编译成class文件交给JVM运行。比如Scala、Kotlin、Groovy、Jython。
既然有了我们静态的class文件,JVM要运行它,那就必须将其加载到JVM的内存结构中,因此有了类装载子系统。类装载子系统将类信息加载到JVM中,并将其字面信息具体映射,JVM用方法区维护这部分数据。
JVM运行java程序,JVM就必须要为每个线程维护其运行时所需要的信息:
- 1、JVM需要知道当前线程运行的指令,即使线程切换回来也不会指令紊乱,并且JVM不能直接依赖物理寄存器,因此JVM模拟实现了PC寄存器。
- 2、JVM为了实现跨平台,采用基于栈的指令集架构,即在运行就算时只要考虑“出栈运算,结果入栈”就行。JVM使用操作数栈来实现运行时的指令操作,伴随的还有用来存储局部变量局部变量表、记录方法该返回到哪个指令的方法返回地址、以及维护调用的方法具体指向哪里的动态链接。操作数栈,局部变量表,方法返回地址,动态链接每个方法一份并且由栈帧管理。每个方法一个栈帧,栈帧由java栈管理,因为进入一个方法可以理解为入栈,方法返回可以理解为出栈。
- 3、JVM实现跨平台,但是和操作系统打交道是不可避免的,比如开辟线程。java使用本地方法接口于C语言交互,并且JVM需要根据不同平台将其适配到不同的本地方法库中的本地方法运行。JVM为此使用本地方法栈维护(老夫对本地方法了解甚少,这句话可能是我瞎忽悠的)
最后JVM运行时需要创建大量对象,对于对象的访问是无规律可循的。不像操作数,当前在用就放到栈顶,用完了就出栈。JVM使用堆对对象进行维护,并进行严格管理。“堆”故名思意就是将很多东西往那里一堆,这个命名非常形象。就好比我们在房间里面放置家具或生活用品,如果我们随手拿,随手放,房间就会乱成一团,造成空间浪费,可能找个吹风机都找不到。因此JVM使用堆对对象的存取进行严格管理。
最后就是我们的执行引擎了:我们class文件只是告诉JVM需要运行的字节码指令,执行引擎负责翻译它,并且执行它。
导航
JVM之垃圾回收
引用:
博客基于宋红康老师的视频教程,所作总结,
java之父:高斯林,目前在谷歌从事人工智能领域。