一、JVM是哪些,能解决哪些问题?

JVM是JavaVirtualMachine(Java虚拟机)的简写,JVM是一种用于计算机的规范,它是一个虚构下来的计算机,是通过在实际计算机上仿真模拟各类计算机功能来实现的。

JVM帮助编程语言屏蔽与具体平台(OS)相关的信息,促使由各中编程语言编撰的编译程序只需在JVM上生成运行的字节码,就可以在多种平台上运行(WORA,WriteOnceRunAnywhere)。

二、JVM体系结构

JVM主要分为类加载器子系统、运行时数据区、执行引擎、本地方式插口以及垃圾搜集模块。

2.1类加载器(ClassLoader)2.1.1类加载器作用

linux 栈溢出攻击原理_类加载器双亲委派机制_JVM体系结构

负责加载并初始化class文件,得到真正的class类,class文件在文件开头有特定的文件标示(例如说编译的版本信息),将class文件的字节码内容加载到显存中,并将这种内容转换成方式区中的运行时数据结构,classLoader只负责class文件的加载,至于它是否可以运行,则有ExecutionEngine(执行引擎)决定。

2.1.2字节码

jvm不能执行java文件,我们编撰的java文件须要经过javac编译器编译成字节码(.class),之后再由JVM执行。javabytecode由单字节(byte)的指令组成,理论上最多支持256个操作码(opcode)。并且实际上java只使用了200左右的操作码,还有一些操作码则保留给调试操作。ClassLoader将.class文件加载并初始化后,得到当前类的Class模板,并将其储存在方式区

使用字节码有哪些优势?java语言通过字节码的形式,在一定程度上解决了传统解释语言执行效率低的问题,同时又保留了解释型语言可移植的特性。所以java程序运行时比较高效,并且因为字节码并不专对一种特定的机器,为此linux格式化硬盘,java程序无须重新编译便可在多种不同的计算机上运行。

解释型语言:在运行的时侯将程序翻译成机器语言。解释型语言的程序不须要在运行前编译(java语言是须要提早编译成字节码的),在程序运行的时侯才进行翻译,专门的类库负责在每位句子执行的时侯解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。(比如:python、php)

2.1.3ClassLoader种类用户自定义加载器Java的类加载机制:启动类加载器-->拓展类加载器-->应用程序类加载器2.1.4双亲指派的机制

工作原理:

类加载器双亲委派机制_JVM体系结构_linux 栈溢出攻击原理

假如一个类加载器收到了类加载恳求,它并不会自已先去加载,而是把这个恳求委托给父类的加载器去执行;假如父类加载器还存在其父类加载器,则进一步向下委托,依次递归,恳请最终将抵达顶楼的启动类加载器;假如父类加载器可以完成类加载任务,就成功返回,若父类加载器未能完成此加载任务,子加载器才尝试自已去加载;

为何使用双亲指派机制:

2.1.5沙箱安全机制

通过双亲指派机制,类的加载永远都是从启动类加载器开始,依次下放,保证你所写的代码,不会污染Java自带的源代码,所以出现了双亲指派机制,保证了沙箱安全

2.2运行时数据区(RuntimeDataArea)2.2.1堆(Heap)

详见显存模型篇

类加载器双亲委派机制_linux 栈溢出攻击原理_JVM体系结构

2.2.2方式区(MethodArea)2.2.3栈(栈帧)

栈管运行,堆管储存

栈也叫栈显存,主管Java程序的运行,是在线程创建时创建。他的生命周期是追随线程的生命周期,线程结束这么栈显存也就急剧释放,对于栈来说不存在垃圾回收问题,只要线程已结束该栈就over了,是线程私有的。8种基本类型的变量+对象的引用变量+实例方式都是在函数的栈显存中分配。

StackOverflowError:​若单个线程恳求的栈深度小于虚拟机容许的深度,则会抛出StackOverflowError(栈溢出错误)。​JVM会为每位线程的虚拟机栈分配一定的显存大小(-Xss参数),因而虚拟机栈才能容纳的栈帧数目是有限的,若栈帧不断进栈而不出栈,最终会造成当前线程虚拟机栈的显存空间用尽,典型如一个无结束条件的递归函数调用,代码见下:

2.2.4本地方式栈(NativeMethodStack)

本地方式栈服务的对象是JVM执行的native方式,而虚拟机栈服务的是JVM执行的java方式。它的具体做法是NativeMethodStack中登记native方式,在ExecutionEngine执行时加载本地方义县。

类加载器双亲委派机制_linux 栈溢出攻击原理_JVM体系结构

2.3执行引擎(ExecutionEngeine)

执行引擎负责解释命令,递交操作系统执行

2.4本地方式插口(NativeInterface)

native:在Java中是一个关键字,有申明,无实现。以线程为例,不要以为线程是属于Java的一个东西,虽然它是属于操作系统底层的,Java中通过Thread类的start()类启动一个线程,

步入Thread的start()的源码,你会听到似乎调用的是start(),但虽然调用的start0()这个方式,最终是由privatenativevoidstart0();这段代码去跟底层做了交互实现linux 栈溢出攻击原理,有申明,无实现,Java到此交由系统去处理了。

三、JVM怎么运行JAVA类3.1java为何要在JVM中运行

JVM体系结构_类加载器双亲委派机制_linux 栈溢出攻击原理

Java作为一门中级语言,其具象程度很高,句型十分复杂。因而未能直接运行在机器硬件上,所以java程序在运行之前,须要对其进行一番转换。转换思路:设计一个面向java语言特点的虚拟机,并通过编译器将Java转换成该虚拟机所能辨识的指令序列(java字节码)。这个虚拟机可以由硬件直接实现,而且更为常见的是由各个平台(Windowsx64,Linux_aarch64等)进行软实现,那么做的意义在于,一旦一个Java程序被转换成Java字节码,这么它便可以在不同平台上的虚拟机里运行,也就是“一次编撰,四处运行”。

虚拟机还有个益处:提供托管环境(ManagedRuntime)。这个托管环境能否取代我们处理一些代码中繁琐并且容易出错的部份,例如显存管理与垃圾回收。据悉还提供了例如:数据越界、动态类型、安全权限等动态复查。使我们能否少写一些业务逻辑无关的代码。

3.2Java虚拟机怎么运行Java字节码

以HotSpot虚拟机为例:

加载由Java文件编译而成的class文件到虚拟机。加载好储存到方式区。实际运行时,JVM会执行方式区中的代码。执行时须要将字节码翻译成机器码linux 栈溢出攻击原理,有两种翻译方法:解释执行与即时编译。解释执行:逐字将字节码翻译成机器码并执行。优势:无需等待编译。即时编译(Just-In-TimeCompilation,JIT):一个方式中所有的字节码都翻译成机器码后再执行。优势:执行效率高。HotSpot外置了多个即时编译器:C1、C2以及Graal(Java10才引入的,实验性的)。C1:Client编译器,面向启动性能要求更高的顾客端GUI程序。C2:Server编译器,面向对峰值性能有要求的服务器端程序,优化手段相对复杂,因而编译时间长。但生成的代码执行效率高。3.3Java虚拟机运行java类3.4Java虚拟机运行java方式首先有个执行栈,储存目前所有活跃的方式,以及它们的局部变量和参数。当一个新方式被调用时,会在执行栈的栈顶压入一个新的栈帧,该方式分配的本地变量和参数会储存在这个栈帧中。跳到目标方式代码执行。方式执行完返回的时侯,本地变量和参数就会被销毁linux压缩命令,该方式所在栈帧会进行出栈操作(栈顶被移除)。返回原先的地址执行。四、即时编译(JustInTimeCompilation)附件:参考资料

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复