JVM基础学习笔记

JVM基础

1.jdk, jre, jvm 关系.

  • JDK 简单理解就是Java开发工具包,是java的核心所在;JRE 是 Java 的运行环境,JVM 也就是常常听到的 Java 虚拟机。

  • JDK是整个Java的核心,包括了 JRE ,同时在 jdk 文件夹 bin 目录中包含了一些Java开发工具(例如:javac、java、javadoc、jar等)。

  • JRE(Java Runtime Environment),即Java运行环境,支持Java程序运行的标准环境,包含JVM标准实现及Java核心类库。

  • JVM ,即Java虚拟机,运行在操作系统之上,存在于内存中,与内存打交道,与硬件没有直接交互,是Java语言实现跨平台的核心。

  • JDK是面向开发者的,JRE是面向使用JAVA程序的用户,JVM是java实现跨平台和系统的媒介所在。
    在这里插入图片描述

2.了解一下未来jdk的新技术发展.

  • 发展会越来越趋于模块化
  • 语言会越来越混合
  • 多核并行
  • 进一步丰富语法
  • 64位虚拟机

3.jvm种类, 我们使用的是哪一种,特点?

JVM的种类有很多,总结出来一般有以下几种:

  • Sun Classic Vm(这个是Sun公司出来的最开始的虚拟机)
  • Exact Vm(这个也是最初的一款虚拟机和上面的Classic Vm齐名)
  • HotSpot Vm(这个是目前用的最多的一款虚拟机,它结合了上面两款虚拟机的特点,还有自己的优势)
  • KVM(它强调简单、轻量、高度可移植,但是运行速度比较慢。在 Android、iOS等智能手机操作系统出现前曾经在手机平台上得到非常广泛应用)
  • JRockit(这款虚拟机和下面的J9以及上面的HotSpot合称为商业用的最大的三款虚拟机)
  • J9(这一款和上面的JRockit和HotSpot合称为商业用的最大的三款虚拟机,这款虚拟机在某些方面做的比HotSpot还要更加的出色)
  • Dalvik(这款虚拟机可谓是挑战者,它并不是JVM,不能直接执行Java的Class文件,但是好像Android在用,性能还挺好的)
  • Microsoft JVM(这是一款没有成功,也没有失败的虚拟机)
  • Azul VM 和 Liquid VM(这两款虚拟机可谓是软硬件的合并,需要和特定的硬件进行绑定从而可以有更加高效的性能)
    我们使用的是HotSpot这一款,它的特点是:继承了Sun Classic Vm和Exact Vm的优点,此外还增加了热点代码侦测的技术

4.为什么叫java 虚拟机,它与 vmware的区别?

Java虚拟机顾名思义就是专门为运行Java程序所编写的一款虚拟机。
Java虚拟机运行的是java指令集
它与VMware的区别是,JVM只是一个虚拟的环境,它并没有去直接连接硬件,而是去模拟一个与硬件相似的环境,而VMware是直接去连接主机上的硬件来使用。
VMware虚拟机运行的是cpu指令集
系统虚拟机:Visual Box,VMware就属于系统虚拟机,他们完全是对物理计算机的仿真,提供了一个可运行完成操作系统的软件平台。
程序虚拟机:代表就是典型的Java虚拟机,它专门为执行单个计算机程序而设计,在Java虚拟中执行的指令我们称之为Java字节码指令。

5.java虚拟机的整体架构

JVM由三个主要的子系统构成: - 类加载子系统 - 运行时数据区(内存结构) - 执行引擎

  • 类加载子系统负责从文件系统或网络中加载Class信息,加载的类信息存放于方法区。除了类信息,方法区还会存放运行时常量池信息,包括字符串字面量和数字常量(Class文件中常量池部分的内存映射)。
  • Java堆在系统启动的时候建立,几乎所有的Java对象都存放在Java堆中,堆空间是所有线程共享的。
  • Java的NIO库允许Java程序使用直接内存,直接内存是在Java堆外的、直接向系统申请的内存。访问直接内存的速度会由于Java堆(避免了在Java堆和直接内存中来回复制数据),读写频繁的场合可能会使用直接内存。Java堆和直接内存的总和受限于操作系统的最大内存。
  • 垃圾回收系统可以对方法区、Java堆和直接内存进行回收,其中Java堆是垃圾收集器的工作重点。对于不再使用的对象,垃圾回收系统会在后台默默查找、标识并释放垃圾对象。
  • 每一个Java虚拟机线程都有一个私有的Java栈,Java栈在线程创建的时候被创建。Java栈中保存着帧信息(存储局部变量表,操作数栈、动态链接、方法出口等信息),方法执行的过程对应栈帧入栈与出栈的过程。
  • 本地方法栈和Java栈类似,用于本地方法(通常用C编写)调用,Java虚拟机允许Java直接调用本地方法。
  • PC(Program Counter)也是每个线程私有的空间,Java虚拟机会为每个Java线程创建程序计数器。任意时刻,1个Java线程总是在执行1个方法,正在被执行的方法称为当前方法。如果当前方法不是本地方法、PC寄存器就会指向当前被执行的指令,如果当前方法是本地方法,PC寄存器的值为undefined。
  • 执行引擎负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成机器码后在执行。

6.字节码的加载流程?

  • 加载:查找并加载类的二进制数据
  • 连接:
    验证:确保被加载的类的正确性
      准备:为类的静态变量分配内存,并将其初始化为默认值
      解析:把类中的符号引用转换为直接引用
        符号引用:通俗的讲,是一种间接引用,如一个类中的方法引用了另外一个类,这是一种符号的表述。
      直接引用:就是通过指针的方式,直接指向了目标对象内存的位置,这样能一下子找到特定的方法。
  • 初始化: 为类的静态变量赋予正确的初始值

在这里插入图片描述

7.java的编译器输入的指令流是一种基于栈的指令集架构, 它有什么优点?

基于栈的指令集架构的优点是:

  • 设计和实现更简单,适用于资源受限的系统;
  • 避开了寄存器的分配难题:使用零地址指令方式分配。
  • 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器容易实现。
  • 不需要硬件支持,可移植性更好,更好实现跨平台

8.能运行在虚拟机上的字节码只能由 javac 编译而来的java源代码产生吗, 除此之外,还有其它哪些语言也可以编译字节码出来?

​ 不是只能由 javac 编译而来的java源代码产生,还有Kotlin,Scala, JavaScript, Groovy等等都可以通过编译器,编译成字节码文件运行到Java虚拟机。

在这里插入图片描述


------------类加载相关------------

1.jvm在什么情况下会加载一个类?问题:怎么测试一个类它被加载上了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xyNlImvk-1657782511301)(E:\JVM\a.png)]

2.类加载到jvm中的过程?每个阶段的工作?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqNG7EGI-1657782511302)(E:\JVM\i.png)]

类加载过程主要分为七个阶段:加载、验证、准备、解析、初始化、使用、卸载。

1、加载:

1)、通过一个类的全限定名加载该类对应的二进制字节流。主要通过类加载器实现。

2)、将字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3)、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区各个类访问该类的入口。(Hotspot 在方法区生成该类)。

2、验证:

1)、文件格式验证:验证类文件的魔术版本号常量等是否符合当前虚拟机支持的范围。

2)、元数据验证:验证类的语义信息,是否符合java语言规范的要求。

3)、字节码验证:验证程序语义是合法的、合乎规范的。主要通过stackmapframe结构。

4)、符号引用验证:虚拟机在将符号引用转化为直接引用,验证符号引用全限定名代表的类是否能够找到,对应的域和方法是否能找到,访问权限是否合法。

3、准备:

准备阶段主要是将类变量(被static修饰符修饰)在方法区进行内存分配并进行初始化。

数据类型 零值 数据类型 零值
int 0 boolean false
long 0L float 0.0f
short 0 double 0.0d
char ‘\u0000’ reference null
byte 0

4、解析:

1)、类或接口解析:将符合引用转化为类的直接引用,并检查访问权限。

2)、字段解析:将字段的符号引用转化为字段所属的类信息或其父类该字段的直接引用,并检查访问权限。

3)、类方法解析:将类方法的符号引用转化为类方法所属的类信息或其父类该字段的直接引用,并检查访问权限。

4)、接口方法解析:将接口方法的符号引用转化为接口方法所属的接口信息或其父类该字段的直接引用,并检查访问权限。

5、初始化:

初始化阶段编译器会将类文件声明的静态赋值变量和静态区域合并生成方法并进行调用。

类加载器:类加载器是“通过一个类的全限定名加载这个类的二进制字节流”的实现,对于任何一个类,都是由类加载器和该类的本身共同确定在虚拟机中的唯一性。

双亲委派模型:

delegation

1、Bootstrap ClassLoader 启动类加载器,负责加载<JAVA_HOME>/lib/rt.jar.

2、Extension ClassLoader 拓展类加载器,负责加载<JAVA_HOME>/lib/ext底下的包

3、Application ClassLoader 应用类加载器,负责加载CLASSPATH路径下的JAVA类库。

4、User ClassLoader 用户自定义的类加载器。

双亲委托模型采用这样的方式加载类:当类加载器收到加载类请求时,首先委托父类加载该类,所有类加载器都采用这种方式,因此所有类加载请求都会到达顶层父类,父类加载不到时再使用该类加载器中加载。这样,类加载器之间就有了一种层级关系,能够保证Java的基础类由相同的类加载器加载,对Java系统的稳定性起到至关重要的作用。

3.jvm中的类加载器的类型及它加载的目标路径?如何自定义一个类加载器加载一个指定目录下的class文件?

​ 了解Java类加载机制应该就会知道,Java提供了3中类加载器:启动类加载器、扩展类加载器和应用程序类加载器。它们分别负责加载不同路径下的类库。

根加载器 (BootStrap ClassLoader)

用来加载JVM提供的基础运行类,即位于%JAVA_HOME%jre/lib 这个目录下面的核心类库。根加载器是所有加载器的父加载器。

扩展类加载器 (Extension ClassLoader)

是根加载器的子加载器,负责 $JAVA_HOME/lib/ext 目录下或者 java.ext.dirs 系统变量指定路径下扩展类的加载。

系统类加载器 (Application ClassLoader)

也叫做应用程序类加载器。是扩展类加载器的子加载器。负责加载用户类路径 classpath 指定的类。

com.my.test.load3.ClassLoaderTest2

​ 在idea中运行 ClassLoaderTest2 类 获取三类加载器的路径 ,可以看出:

启动类加载器所加载的是JVM中最底层的类,加载时的搜索路径是sun.boot.class.path。

扩展类加载器是用来加载java的一些库的,加载时的搜索路径是java.ext.dirs

应用类加载器搜索路径是java.class.path

4.什么是双亲委派模型,有什么作用?

双亲委派模型有两个好处:

  1. 向上委托给父类加载,父类加载不了再自己加载,防止加载同一个.class。通过委托去询问上级是否已经加载过该.class,如果加载过了,则不需要重新加载。保证了数据安全。
  2. 避免重复加载,防止Java核心api被篡改。通过委托的方式,保证核心.class不被篡改,即使被篡改也不会被加载,即使被加载也不会是同一个class对象,因为不同的加载器加载同一个.class也不是同一个Class对象。这样则保证了Class的执行安全。

加载器自上而下分别为,启动类加载器(Bootstrap ClassLoader), 拓展类加载器(Extension ClassLoader), 系统类加载器(Application ClassLoader) , 自定义类加载器(Custom ClassLoader)

在这里插入图片描述

双亲委派模式是Java1.2之后引入的,其工作原理是,如果其中一个类加载器收到了类加载的请求,它并不会自己去加载而是会将该请求委托给父类的加载器去执行,如果父类加载器还存在父类加载器,则进一步向上委托,如此递归,请求最终到达顶层的启动类加载器。如果父类能加载,则直接返回,如果父类加载不了则交由子类加载,这就是双亲委派模式。

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素, java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java APlI发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

5.类加载器是如何确定一个类在jvm中的唯一性的? 两个类来源于同一个Class文件,被同一个虚拟机加载,这两个类一定相等吗?

自定义的类加载器myLoader可以加载与自己在同一路径下的Class文件。我们使用这个类加载器去加载了一个名为“com.my.test.load4.MyClassLoaderTest ”的类,并实例化了这个类的对象。

com.my.test.load4.MyClassLoaderTest

两行输出结果中,从第一句可以看出,这个对象确实是类com.my.test.load4.MyClassLoaderTest实例化出来的对象,但从第二句可以发现,这个对象与类com.my.test.load4.MyClassLoaderTest 做所属类型检查的时候却返回了false。

这是因为虚拟机中存在了两个MyClassLoaderTest类,一个是由系统应用程序类加载器加载的,另外一个是由我们自定义的类加载器加载的,虽然都来自同一个Class文件,但依然是两个独立的类,做对象所属类型检查时结果自然为false。

6.tomcat的类加载器有哪些?

Tomcat类加载器

一方面出于架构考虑,一方面也是出于servlet规范考虑(每个应用要有单独的类加载器),应用服务器通常自定义类加载器已实现更加灵活的控制。

隔离性: web应用类库要相互隔离,避免依赖库互相影响,
**灵活性:**指针对某一个应用重新部署时不用加载所有应用的类库。
性能: 每个应用都有一个类加载器,web类重新加载时不涉及其他应用的类,速度更快。

tomcat类加载方案(Tomcat Bootstrap类 是由 java类加载器中的 System Class Loader 来加载的)
在这里插入图片描述
tomcat也提供了三个基础类加载器和web应用类加载器
Common: 以System类加载器作为父类,是tomcat顶层的公用类加载器,路径由conf/catalina.properties中的common.loader指定,默认指向 CATALINA_HOME/lib下的包。负责加载Tomcat应用和Web应用可见的jar包,如Servlet规范包等。
**Catalina:**以Common类加强在其为父类加载器,是用于加载Tomcat应用服务器的类加载器,路径为server.loader,默认为空,使用Common类加载器进行加载。只负责加载tomcat应用类,这些类对web应用不可见。使得web应用和tomcat实现松耦合。
Shared: 以Common类加强在其为父类加载器,是所有web应用类加载器的父类加载器,路径为shared.loader,默认为空个,使用Common类加载器作为web应用类加载器的父类加载器。负责加载web应用共享的类,Tomcat服务器不可见。
**Web应用:**以shared类加载器为父类加载器,加载/WEB-INF/classes目录下未压缩的Class和资源文件以及/WEB-INF/lib下的jar包,该类加载器只对当前应用可见,其他应用不可见。

默认情况下三个基础类加载器都是同一个(Common)但是可以通过配置使三个基础类加载器各自生效。
CATALINA_HOME/bin下的类作为启动入口由System类加载器进行加载。

共享性: 通过common类加载器实现 tomcat应用和web应用的jar包共享,通过shared类加载器实现 web应用间jar包共享。

隔离性: 实现了tomcat服务器和web应用的隔离,以及各个web引用之间的隔离。

默认情况下三个基础类加载器都是Common,这种情况下是通过JVM的安全策略许可实现禁止web应用使用服务器实现类。

web应用类加载器

java默认类加载器的委派逻辑
1 从缓存中加载
2 如果缓存没有,从父类加载器进行加载
3 父类加载器没有则,从当前类加载器进行加载
4 如果都没有抛出异常

**tomcat类加载器的委派逻辑有所不同,进行类加载时除了JVM基础类库外,首先尝试通过当前类加载器进行加载,然后才进行委派。**Servlet规范相关的API禁止通过web应用类加载器进行加载,因此这些包不要放在web应用中。

web应用类加载器默认加载顺序如下:
1 从缓存中加载
2 如果没有 从JVM的Bootstrap类加载器加载
3 如果没有 从当前类加载器进行加载(WEB-INF)
4 如果没有 从父类加载器进行加载,由于父类加载器采用了默认的委派模式,所以加载顺序为System Common Shared

**Tomcat 提供了delegate属性用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值