JVM的体系结构是什么?
完整来说JVM结构包含三个部分:
a. 类装载器
b. 运行时数据区(JVM的内存模型)
c. 执行引擎
如图所示:
![](https://img.haomeiwen.com/i20347625/d74ae0070c35655f.png)
说说工作流程,Class文件在硬盘中被读取然后由Class loader类加载器将Class文件加载到内存中,然后再将各个类加载到JVM内存中去,这时候的class类就是一个元数据模板,而你在实际需要的时候需要new一个对象实例时候。
类加载器(ClassLoader):
1.启动类加载器(Bootstrap)是由C++编写的,主要负责加载<JAVA_HOME>\lib目录中或被-Xbootclasspath指定的路径中的并且文件名是被虚拟机识别的文件。它等于是所有类加载器的爸爸。
2.扩展类加载器(Extension)java语言编写的,独立于虚拟机,主要负责加载<JAVA_HOME>\lib\ext目录中或被java.ext.dirs系统变量所指定的路径的类库。
3.应用程序类加载器(AppClassLoader)java语言编写,也叫系统类加载器,独立于虚拟机。主要负责加载用户类路径(classPath)上的类库,如果我们没有实现自定义的类加载器那这玩意就是我们程序中的默认加载器。
(1-3是虚拟机自带的类加载器)
4.java.lang.ClassLoader的子类,用户可以定制类的加载方式。(4是用户自定义的类加载器)
JVM的类加载存在一个叫双亲委派机制和沙箱安全机制。
双亲委派机制:如果一个类加载器需要加载类,那么首先它会把这个类请求委派给父类加载器去完成,每一层都是如此。一直递归到顶层,当父加载器无法完成这个请求时,子类才会尝试去加载。这里的双亲其实就指的是父类,没有mother。父类也不是我们平日所说的那种继承关系,只是调用逻辑是这样。
沙箱安全机制:它主要 用于保护虚拟机的内部资源不被虚拟机外部运行的恶意或有漏洞的代码侵犯。例如自定义一个java.lang包下的String类,在运行时,jvm会自动加载它自己带的java.lang.String 类,而不会去加载你事先定义的那个String类,你如果在你自己定义的那个String类下加上一个main函数,你运行时它会报错,错误内容大致意思是说系统自带的String类里面没有main函数。
本地方法栈+本地方法接口+本地方法库
本地方法是java代码引用的c或者c++写的底层方法,java底层的一些实现是基于c和c++实现的;而本地方法栈它则是这些方法执行的时候所在的内存空间,里面分配了c语言方法执行所需要的变量,方法,等等。而本地方法接口是基于本地方法执行所需要调用的一些操作系统里面的方法的接口,本地方法库则是操作系统自带的一些方法库。其实这些都是为java底层运行做了补充!
JAVA栈
1.描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
2.生命周期与线程相同,线程运行完毕后,相应的内存自动回收。(线程私有)
3.这个区域可能有两种异常:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常(如:将一个函数反复递归自己,最终会出现这种异常)。如果JVM栈可以动态扩展(大部分JVM是可以的),当扩展时无法申请到足够内存则抛出OutOfMemoryError(OOM)异常
方法区
1.方法区域是全局共享的,比如每个线程都可以访问同一个类的静态变量。它存储了已被JVM加载的类信息、静态变量、编译器编译后的代码等。如,当程序中通过getName、isInterface等方法来获取信息时,这些数据来源于方法区。
2.由于使用反射机制的原因,虚拟机很难推测哪个类信息不再使用,因此这块区域的回收很难!另外,对这块区域主要是针对常量池回收。
3.当方法区无法满足内存分配需求时,会抛出OutOfMemoryError。
程序计数器
1.当前线程正在执行字节码行号指示器。
2.为了线程切换后能够恢复到正确的执行位置,每个线程都需要一个独立的程序计数器。(线程私有)
3.当线程执行的是一个Java方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址。
4.当线程执行的是一个Native方法,则计数器的值为空(Undefined)(原因:native方法体并不是由Java字节码构成,所以无法应用“Java字节码地址”的概念,所以JVM规范规定,当执行Native方法时,计数器的值未定义(任何值都可以))。
5.该区域是唯一一个在JVM规范中没有规定任何OOM情况的区域。
堆
1.堆是Java虚拟机所管理内存最大的一块,被线程全局共享,在虚拟机启动时创建。
2.几乎所有的对象实例都在堆中分配内存。
3.堆是垃圾收集器的主要区域。
4.根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。
5.如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
网友评论