JVM(Java虚拟机)

目录

1.JVM 简介

2. JVM 运行时数据区

2.1程序计数器

2.栈

3.堆

4.方法区

3.类加载

1.loading

2.linking

扫描二维码关注公众号,回复: 15260763 查看本文章

1.验证

2.准备

3.解析

3.Initializing

4.双亲委派模型

5.JVM垃圾回收机制

1.劣势

2.回收什么

3.垃圾回收具体怎么回收

1.找垃圾

方法:

问题:

2.释放垃圾


1.JVM 简介

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。

2. JVM 运行时数据区

2.1程序计数器

每个线程都有一个

1.作用:记录当前线程执行的行数(相当于一个书签)

内存中最小的区域,保存下一条要执行的指令的地址在哪里.

程序要运行,JVM要把字节码加载起来,放在内存中,程序就会一条一条把指令从内存中放到CPU内存上执行,就要记住当前执行的是哪一条了

2.栈

1.存储内容:局部变量和方法调用信息

一个进程只有一份

方法调用的时候,每次调用一个新的方法,就涉及到"入栈"操作,每次执行完方法,就涉及到"出栈"操作

栈空间很小,如果递归条件没有写好,可能会出现栈溢出

3.堆

一个进程有一份,多个线程共用一个堆

1.内存中空间最大的区域

2.存储内容:new的对象,对象的成员变量(不包含静态变量)

4.方法区

1.存储内容:类对象(包含静态成员)

.java->.class(二进制字节码).class会被加载到内存中,被JVM构造成类对象

3.类加载

把.class文件,加载到内存中,构成类对象

1.loading

找到对应的.class文件,打开并读取.class文件,同时初步生成一个类对象

2.linking

建立多个实体直接的联系

1.验证

验证读到的内容是不是和规范中规定的格式,完全匹配

如果读到的数据格式不符合规范,就会;类加载,并抛出异常

2.准备

为类中的变量(静态变量)分配内存并设置类变量初始值

3.解析

java虚拟机把常量池中的符号引用替换成直接引用的过程,是初始化常量的过程

.class文件的结构体中初识情况下是记录了编号,根据编号找到对应内容,填充到类对象中

3.Initializing

真正对类对象进行初始化,尤其是针对静态成员

4.双亲委派模型

JVN中类加载器,根据类的全限定名找到.class文件的过程

默认的类加载器,主要是3个~~

1.BootStrapClassLoader负责加载标准库中的类(String, ArrayList, Random, Scanner.....)

2.ExtensionClassLoader负责加载JDK扩展的类.

3.ApplicationClassLoader 负责加载当前项目目录中的类

双亲委派模型:描述了找目录的过程,就是上述类加载器是如何配合的

1)考虑加载 java.lang.String

1>程序启动,进入AppliactionClassLoader类加载器

2>ApplicationClassLoader就会检查下,它的父加载器是否已经加载过了.如果没有,就调用父类加载器ExtensionClassLoader

3>ExtensionClassLoader也会检查下,它的父加载器是否加载过了.如果没有,就调用父类加载器BootStrapClassLoader

4>BootStrapClassLoader也会检查下,它的父加载器是否加载过,自己没有父亲,于是自己扫描自己负责的目录

5>java.lang.String这个类在标准库中能找到!!!直接由BootStrapClassLoader负责后续的加载过程.查找环节就结束了

2)考虑加载自己写的Test类

1>程序启动,进入AppliactionClassLoader类加载器

2>ApplicationClassLoader就会检查下,它的父加载器是否已经加载过了.如果没有,就调用父类加载器ExtensionClassLoader

3>ExtensionClassLoader也会检查下,它的父加载器是否加载过了.如果没有,就调用父类加载器BootStrapClassLoader

4>BootStrapClassLoader也会检查下,它的父加载器是否加载过,自己没有父亲,于是自己扫描自己负责的目录,没扫描到!回到子加载器继续扫描

5>ExtensionClassLoader也扫描自己负责的目录,也没扫描到,回到子加载器继续扫描.

6>ApplicationClassLoader也扫描自己负责的目录,能找到Test类,于是进行后续加载.查找目录的环节结束.

如果最终ApplicationClassLoader 也找不到,就会抛出 ClassNotFoundException 异常!!

5.JVM垃圾回收机制

1.劣势

1.影响额外的开销

2.影响程序的流畅运行

2.回收什么

1.程序计数器

固定大小,不涉及到释放,不需要GC

2.栈

函数执行完毕,对应的栈帧就自动释放

3.堆

最需要GC的,代码中大量的内存都在堆上

4.方法区

进行"类加载要释放内存,卸载操作很低频的操作

只释放完全不使用的

回收的基本单位是对象不是字节

3.垃圾回收具体怎么回收

1.找垃圾

方法:

1.基于引用计数

针对每个对象都有额外引入一小块内存,保存有对少个引用指向他

当内存不使用(引用计数为0),可以释放

例如:函数调用创建对象,分配内存,方法结束,局部变量和栈帧一起释放,使引用计数为0,就认为这个对象是个垃圾

缺陷:

1.空间利用率低,要是对象很小,空间利用率就降低

2.有循环引用的问题

两个对象t1,t2分别引用对方的属性,此时两个对象的引用计数为2,要是两个对象都设置为null,此时引用计数不为0,无法释放,因为引用长在彼此的身上,外界的代码无法访问到这两个对象,此时两个对象不能使用,不能释放,就会出现内存泄漏

2.基于可达性分析

通过额外的线程,定期对整个内存空间的对象进行扫描

有起始位置,把可以访问到的对象标记一遍,没有标记的就是不可达,就是垃圾

起始位置:

栈上的局部变量

常量池中的引用指向对象

方法区中的静态成员指向的对象

优点:克服引用计数的缺点:空间利用率低,循环使用

缺点:系统开销大,遍历一次很慢

问题:

2.释放垃圾

1.标记-清除

标记:可达性分析的过程

清除:释放内存

直接释放内存,分布是离散的,问题"内存碎片"

2.复制算法

把不是垃圾的拷贝到另一半,把原来 空间整体都释放

问题:

内存利用率低

保留对象多,释放对象少时,开销大

3.标记-整理

根据复制算法进行改进

把保留的对象拷贝到前面(直接覆盖要释放的对象),多余的删除

空间利用率高,没有解决复制/搬运的开销

JVM实现会把多种方案结合

分代回收

针对对象分类:(根据对象的年龄分类),一个对象熬过一轮GC的扫描,长一岁

不同年龄用不同的方案

1.刚创建的对象放在伊甸区

2.伊甸区对象熬过一轮GC扫描,被拷贝到幸存区(使用复制算法)

3.在后续的GC,幸存区对象在两个幸存区中来回拷贝(复制算法),每轮都会淘汰幸存者

4.持续若干轮后,进入老年的代

因此老年代的GC扫描频率大大低于新生代,老年代中使用标记整理的方式进行回收

猜你喜欢

转载自blog.csdn.net/qq_53190275/article/details/130426449