目录
前言
最近想系统的简单回顾下jvm,于是打算以宏观到微观这样的方式,来了解下jvm结构。
开始
个人愚见,jvm既然是虚拟机,那在表面看来得和物理机差不多吧,比如物理机的执行引擎、内存等,jvm应该也得有,那jvm规范就对jvm应该整体结构和应要求做了规定,比如得有个执行引擎、运行时内存等,还得有个类加载子系统,因为引擎是执行字节码指令的,得弄个把字节码加载到内存的东西啊,话不多说,先来张图看看jvm长啥样,到底漂不漂亮。
jvm结构大致如上图所示,执行流程为,类加载子系统加载cass文件,将文件中的静态量放到方法区中,并且在内存中创建Class对象(注意虚拟机规范并未对哪部分内存做限定,hotspot的Class对象是在方法区中的),整个类加载过程也要分为7个阶段,这里不做细节展开,那执行引擎的工作呢,执行引擎是面向虚拟机栈的操作数栈的,比如要做个a+b,其中a=1,b=1,那首先得先把a从局部变量表中压栈到操作数栈,b也是,然后进行求和返回,这里做事的就是执行引擎,这个a+b在字节码上对应几个虚拟机指令(如 iload),引擎的工作就是执行指令(其实和物理机一样,物理机的引擎也是执行本地机器指令的),运行时数据区就是内存嘛,因为引擎不提供大存储嘛(对比物理机),这里涉及JMM内存模型,稍后说说,剩下的本地方法接口,这个就简单了,有历史原因,c早期的盛行,也有客观原因,要进行系统调用,到这总体上也就对jvm有个整体印象了。
扩展思考
扩展一
java线程——我们知道在操作系统上执行个程序,对应着一个进程,换句话说,就是程序是通过进程执行的,那我们的java代码要执行也得整个类似线程的东西,因为jvm引擎与操作数栈打交道,而操作数栈是虚拟机栈栈帧结构,虚拟机栈是java线程来执行的。
扩展二
JMM——java内存模型这个标准是干啥的,我们知道物理机有内存,那jvm也有运行时数据区,那物理机还有各种缓存呢,比如L1、L2、cpu高速缓存等(为啥整这些东西,因为cpu太聪明了,运行飞快,内存的读写也跟不上啊),那jvm呢,jvm线程和内存的关系做了个抽象,就是JMM,谈到JMM还必须的说的就是线程安全。
扩展三
线程安全——因为JMM规范,所以必须谈谈线程安全问题,运行时数据区可进一步细分为,线程私有内存(虚拟机栈、本地方法栈、程序计数器),和共享内存(堆、方法区),因为线程私有内存的存在会引发线程安全为题,因为线程对共享变量的读写是在实际是对私有内存中共享变量副本的读写,而非对主存的直接读写。
扩展四
锁——提到线程安全就得说一下锁,并发编程要处理的2个关键问题就是线程间通信和同步,那其实java中的做的就是同步问题,多线程读写同时读写共享变量会有并发安全问题,那让线程排队访问就避免了这个问题,所以有了锁的概念,提到锁可能要延伸到aqs和cas、volatile等相关知识点。
扩展五
垃圾收集器——既然jvm有这么个内存区域,那得对这个内存区域进行管理啊,别只用不维护(垃圾收集),那用着用着就用坏了了啊(内存溢出),那作为垃圾收集器要明确自己的工作职责和范围,首先得知道维护哪个片区(堆内存、方法区,注意方法区为堆的逻辑组成部分,但虚拟机规范不要求必须实现这个区域的垃圾收集),堆分为年轻代和老年代,年轻代又分为伊甸园区、幸存区1、幸存区2,方法区jdk7是永久代、jdk8是元空间,其次还得知道哪些是可回收的(可达性分析),还得知道咋样工作有效率,得结合一些算法和多线程。