jvm-Java虚拟机

发布于:2025-02-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

一.什么是jvm

jdk-Java开发工具包

jre-Java运行时环境

jvm-Java虚拟机

像C++这样的语言就是直接编译成了二进制的机器指令,不同的cpu上面支持的指令不一样,如果是换了操作系统,可能就会需要重新编码.

而Java就想要只是使用一套编码,在各个操作系统上都是使用一套编码.

我们先通过javac把.java文件转换成.class文件(字节码文件,包含的就是Java字节码.字节码就是Java自己搞的一套cpu指令).然后在某个具体的系统上执行.此时通过jvm将Java自己的字节码文件(二进制指令)转换成对应的cpu能识别的机器指令.

在这中jvm就像是一个翻译官.负责将Java字节码文件转换成对应的系统的cpu可执行的指令.

当前的主流的jvm:HotSpot VM

二.JVM中的内存区域划分

jvm其实也是一个Java进程.进程在运行的过程中需要从操作系统申请资源.

如果定义一个变量,就会申请,变量申请到的内存就是jvm从操作系统中申请的内存

jvm申请到空间后会划分出几个区域,每个区域都有不同的作用

1.堆:代码中new出的对象,对象中持有的非静态成员变量都会存在堆区中,一个jvm中只有一份

2.栈:包含了方法的调用关系,成员变量也在栈区中,一个jvm中可能有多份

3.程序计数器:存储下一条要执行指令的地址(表示接下来 要干啥)

4.元数据区:一个程序中有哪些类,每个类中有哪些方法,每个方法包含哪些指令

三.JVM的类加载机制

类加载指的是,把.class文件从硬盘上读取到内存中,并进行验证和解析的过程.

类加载大致可以分为5个步骤

1.加载:把硬盘上的.class文件找到,打开文件,读取到文件内容(这里读到的就是二进制文件)

这里我们如何查找.class文件 :双亲委派模型

   jvm中进行类加载的操作,有一个专门的模块,就是"类加载器"(ClassLoader)

   jvm中的类加载器默认是有三个的

  类加载器的作用,给一个"全限定类名",找到对应的.class文件

"全限定类名":java.lang.String(带有包名的类名)

BootstrapClassLoader(负责扫描标准库的目录)

ExtensionClassLoader(负责查找扩展库的目录)

ApplicationClassLoader(负责当前项目代码目录以及第三方库目录)

上述三个类加载器的关系就是:BootstrapClassLoader是爷爷,ExtensionClassLoader是爸爸

ApplicationClassLoader是儿子

双亲委派模型的工作流程:

上述设定就是为了确保这几个类加载器的优先级

也可以有效避免自己写的类和标准库类的名字重复,导致标准库的功能失效 

我们可以通过自己写类加载器来破坏上述的规则       

2.验证:验证.class文件是否合法

3.准备:给类对象申请内存空间

4.解析:Java虚拟机中将常量池的符号引用替换为直接引用的过程,也就是初始化常量的过程.

符号引用:在文件中不存在地址这样的概念.此处文件中填充给s的"hello"的偏移量就是"符号引用"

接下来把文件加载到内存中.此时"hello"就有地址了,此时s将偏移量转换为真正的地址

5.初始化:针对类对象完成初始化

 四.JVM中的垃圾回收算法(GC)

垃圾回收算法的主要目的是释放内存

引入垃圾回收算法后就不再需要我们自己手动释放内存,程序会自己判定某个内存是否会继续使用,如果不用就会释放掉.

垃圾回收算法的问题:STW(stop the world)问题

 触发垃圾回收机制可能会使代码的其他业务逻辑被迫暂停

在JVM的内存划分中,垃圾回收的主战场就是jvm的堆区

垃圾回收,本质上就是回收对象

1.垃圾回收具体是怎样展开的?

(1)识别出垃圾,哪些是垃圾,哪些不是垃圾

如果一个对象没有一个引用指向它,就视为无法被代码使用,于是就会被回收

成员变量在出了方法的括号后就会被销毁

像下方动画演示,t在方法执行完毕后就被销毁了,此时就没有引用指向new Test()

所以new Test就被回收了

 如果有更多的引用指向同一个对象,情况不好办了

(a)解决办法
●1引用计数

这种思想方法,并没有在JVM中使用,一般Python/PHP会使用

 ●可达性分析(JVM使用的是这个)

(2).把标记为垃圾的对象进行释放

 (a).标记_清除

把标记为垃圾的对象直接释放掉

 (b)复制算法

规避了内存碎片问题,但是占用了更多的内存空间

(c)标记-整理
 

虽然解决了内存碎片的问题,但是开销却很大

 (3)分代回收(important)

引入对象的年龄的概念.

JVM中,有专门负责扫描的线程.一个对象,如果被扫描了一次,不是垃圾(不用回收),年龄+1

JVM会根据对象年龄的差异把整个堆的部分分为两个大的部分

新生代(伊甸区,两块生存区):年龄较小的对象和老年代:年龄较大的对象

(a)当我们new一个新的对象,就会存储在伊甸区中,按照规律,伊甸区的对象大部分活不过第一轮GC,大部分都是"朝生暮死",生命周期很短

(b)第一轮GC完事之后,少数在伊甸区存活下来的就会通过复制算法,拷贝到生存区.后续线程还会对伊甸区进行扫描.同时还会扫描生存区域.生存区也会大部分被标记为垃圾,少部分存活的,通过复制算法复制到另一个生存区中.只要是这个对象能够在生存区中继续存活.就会被复制算法再拷贝到另一个生存区中.每经历一次GC扫描.对象的年龄就会+1.

(c)如果这个对象经历了几次扫描依然建在.JVM就会把他从生存区复制到老年代.

(d)老年代对象也会被GC扫描,但是扫描的频次会大大降低.

(e)对象在老年代寿终正寝.此时JVM也会按照标记-整理的方式释放内存


网站公告

今日签到

点亮在社区的每一天
去签到