如果帮到你可以帮忙点个赞吗谢谢
JVM探究
·JVM、JDK、JRE三者的区别?
JVM(Java Virtual Machine):是Java虚拟机,源文件.java在虚拟机中通过编译器编译字节码文件.class,是整个Java实现跨平台的最核心的部分。
JDK(Java Development Kit):开发工具,就是很多开发时使用到的工具比如javac.exe编译工具和java.exe执行工具.我们可以到JDK目录下的bin目录下找到它.
JRE(Java Runtime Environment):即java运行环境,作用是运行别人写好的程序(因为它并不是一个开发环境,因此它没有包含任何开发工具(编译器和调试器),只是针对使用Java程序的用户).
三者的关系是JDK包含JRE包含JVM Java运行步骤是源码(.java)-->javac编译器--->字节码文件(.class)-->Java解释器---->机器码文件
从.java的源代码编译成.class的字节码,就是为了使Javas程序只生成在Java虚拟机上运行的目标代码.class字节码,这样就可以在多种平台不加修改地运行.JVM在执行字节码时,才把其解释成具体平台的机器码指令执行.
因此,JVM的作用就是将字节码文件解释成机器码文件,并且可以针对不同的操作系统有不同的JVM实现,从而实现跨平台的保障.
作用二:Java中的所有类必须被装载到JVM中才能运行,这个装载的工作是由JVM中的类装载器完成,类装载器所做的工作实质是把类文件从硬盘读取到内存中JVM堆中央处理器(CPU)所执行的一种软件操作,用于执行编译过的Java程序码(Applet与应用程序).
所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。当然只有JVM还不能成class的执行,因为在解释class的时候JVM需要调用解释所需要的类库lib,而jre包含lib类库。
·请你谈谈你对JVM的理解?
java文件编译成一个.class文件,然后到JVM里面加载运行
答:JVM是Java虚拟机,其内部体系结构分为三部分:类装载器(ClassLoader)、运行时数据区、执行引擎
类装载器
每一个JVM都由一个类装载器子系统是负责加载程序中的类和接口,并且赋予唯一的名字。每一个JVM都有一个执行引擎(execution engine),负责执行被加载类中包含的指令。JVM的两种类装载器包括启动类装载器和用户自定义装载器.启动类装载器是JVM实现的一部分,用户自定义类装载器是Java程序都是一部分,必须是 ClassLoader类的子类,
执行引擎
它或许在执行字节码,或者在执行本地方法
主要的执行技术有:解释,即时编译,自适应优化,芯片级直接执行其中的解释属于第一代的JVM,即时编译JIT属于第二代JVM,自适应优化则是吸取两代的经验,采取两者结合的方式.
自适应优化:开始对所有代码都采取解释执行的方式,并监视代码执行情况,如何对这些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行仔细优化.如果方法不再频繁使用,则取消编译过的代码,仍对其解释执行.
运行时数据区
主要包括:
-
方法区(Method Area):线程共享区域,用于储存已被虚拟机加载的类信息、常量、静态变量,即编译器编译后(.java编译成.class)的代码,方法区也称持久代(Permanent Generation),主要存放java类定义信息,与垃圾回收(GC)没啥关系,但不是没有GC,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载.运行时常量池,方法区的一部分,虚拟机加载Class后把常量池中的数据放入运行时常量池.持久代在物理层面时在堆里的,但是在逻辑层面是在方法区里,这是因为在物理上方法区也是在堆中,但是由于功能和作用的区别,逻辑方法上方法区是独立于堆的.方法区是规范,永久代是Hotspot针对该规范进行的实现。
-
堆(Heap):线程共享区域,是JVM中最大的一块区域,这个区唯一的目的就是存放对象实例,几乎所有对象实例都在这里分配.
1)新生代(Young Generation):包括Eden区,From Survivor区,To Survivor区,系统默认大小Eden:Survivor=8:1
2)老年代(Tenure Generation):在年轻代经历了N次垃圾回收后仍存活的对象,就会放到老年代中.因此可以认为老年代中存放的都是一些生命周期较长的对象.
-
Java虚拟机栈(Java VM Stack):就是平时说的栈内存,线程私有,是在线程创建时创建,它的生命周期是跟随线程的生命周期,线程结束时栈内存也会释放,所以对此不存在垃圾回收问题,只要线程结束该栈就释放.是Java方法执行时的内存模型,每个方法在执行时都会创建一个栈帧(用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的java虚拟机栈的栈元素)用于存储以下内容:
1)局部变量表:32位变量槽,存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double八种(String是引用类型))、对象引用、returnAddress类型(它指向了一条字节码指令的地址).
2)操作数栈:基于栈的执行引擎,虚拟机把操作数栈作为它的工作区,大多数指令都要从这里弹出数据、执行运算,然后把结果压回操作数栈.
3)动态连接:每个栈帧都包含一个指向运行时常量池(方法区的一部分)中该栈帧所属方法的引用.持有这个引用是为了支持方法调用过程中的动态连接.Class文件的常量池有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数.这些符号引用了一部分会在类装载器或者第一次使用的时候转化为直接引用,这种转化称为静态解析;另一部分将在每一次的运行期间转化为直接应用,这部分称为动态连接.
4)方法出口:返回方法被调用的位置,恢复上层方法的局部变量和操作数栈,如果无返回值,则把它压入调用者的操作数栈.
-
本地方法栈:本地方法栈是线程私有,与虚拟机栈类似,是为native方法服务.(在Hotspot中和虚拟机Java栈合二为一,但是逻辑上是两个东西)
-
程序计数器:是一块较小的内存空间,可以看作当前线程所执行的字节码行号指示器,注意点:
1)程序计数器是线程私有,各线程之间互不影响
2)如果正在执行java方法,计数器记录的是正在执行的虚拟机字节码指令地址
3)如果执行native方法,这个计数器为null
4)程序计数器也是在Java虚拟机规范中唯一没有规定任何OutOfMemoryError异常情况的区域.
·java8虚拟机和之前的变化、更新?
Hotspot取消了永久代,方法区的实现变成了元空间(Metaspace),并且与Java7不同,元空间不再与堆连续,而且是存在于本地内存,并且常量池也从堆中到了元空间.元空间是逻辑上存在,物理上不存在(因为储存在本地磁盘里),所以不算是在JVM中,也就是说没有占用堆内存.
·什么是OOM(内存溢出),什么是栈溢出(Stack overflowError)?怎么分析?
虚拟机在扩展栈时无法申请到足够的内存空间,则会抛出OOM;StackOverflowError代表的是,当栈深度超过虚拟机分配给线程的栈大小时就会出现此error。
·JVM的常用调优参数有哪些?
-Xms数值 设置初始化堆大小
-Xmx数值 设置堆最大内存
-XX:PrintGCdetails 打印gc详细信息
-XX:SurvivorRatio=8 设置新生代Eden和Survivor比例为8:2;
·内存快照如何抓取?怎么分析Dump文件?
有两个工具,一个是MAT,一个是JPofiler
用参数
-XX:+HeapDumpOnOutOfMemoryError
可以把OOM给dump下来,然后通过对应使用的工具进行查看,举例来说JPofiler里面可以查看具体发生OOM的线程是哪个,最大对象是哪个等等
·谈谈JVM中,类加载器的认识? rt-jar ext application
类加载器分类:
1.虚拟机自带的加载器
2.启动类(根)加载器(BootstrapClassLoader):加载jre/lib/rt.jar
3.扩展类加载器(ExtClassLoader):加载jre/lib/ext/*.jar
4.应用程序加载器(AppClassLoader):加载classpath上指定的类库
还有双亲委派机制等保障安全的机制。具体看下文
JVM的位置
JVM是用c语言写的
JVM是在操作系统(Window,Linux,Mac)上面
JVM的体系结构
粗略的体系结构
方法区是特殊的堆,JVM调优99%是在堆里
详细的体系结构:
栈存的是地址,堆存的是地址对应的属性和值.
类加载器
什么是类加载器?
类加载器是jre的一部分,负责动态将类添加到Java虚拟机。
作用:
(1)加载Class文件
下面是一个Car car1 =new Car()的图解分析
下面是代码分析:
Null:Java调用不到。Java早期的名字:C+± - Java = C++:去掉繁琐的东西,指针,内存管理~ Java语言保留了C的接口&#