JVM快速入门

JVM的位置

jvm在操作系统(OS)之上

jre--jvm=>linux,mac=>intell

Java文件运行的方法

img

① 类加载器

如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个 类加载器 中,它就像一个搬运工一样,会把所有的 .class 文件全部搬进JVM里面来。

img

② 方法区

方法区 是用于存放类似于元数据信息方面的数据的,比如类信息,常量,静态变量,编译后代码···等

类加载器将 .class 文件搬过来就是先丢到这一块上

③ 堆

主要放了一些存储的数据,比如对象实例,数组···等,它和方法区都同属于 线程共享区域 。也就是说它们都是 线程不安全

④ 栈

这是我们的代码运行空间。我们编写的每一个方法都会放到 里面运行。

我们会听说过 本地方法栈 或者 本地方法接口 这两个名词,不过我们基本不会涉及这两块的内容,它俩底层是使用C来进行工作的,和Java没有太大的关系。

⑤ 程序计数器

主要就是完成一个加载工作,类似于一个指针一样的,指向下一行我们需要执行的代码。和栈一样,都是 线程独享 的,就是说每一个线程都会有自己对应的一块区域而不会存在并发和多线程的问题。

二.类加载器的介绍

之前也提到了它是负责加载.class文件的,它们在文件开头会有特定的文件标示,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构,并且ClassLoader只负责class文件的加载,而是否能够运行则由 Execution Engine 来决定

2.1 类加载器的流程

从类被加载到虚拟机内存中开始,到释放内存总共有7个步骤:加载,验证,准备,解析,初始化,使用,卸载。其中验证,准备,解析三个部分统称为连接

2.1.1 加载

  1. 将class文件加载到内存
  2. 将静态数据结构转化成方法区中运行时的数据结构
  3. 在堆中生成一个代表这个类的 java.lang.Class对象作为数据访问的入口

2.1.2 链接

  1. 验证:确保加载的类符合 JVM 规范和安全,保证被校验类的方法在运行时不会做出危害虚拟机的事件,其实就是一个安全检查
  2. 准备:为static变量在方法区中分配内存空间,设置变量的初始值,例如 static int a = 3 (注意:准备阶段只设置类中的静态变量(方法区中),不包括实例变量(堆内存中),实例变量是对象初始化时赋值的)
  3. 解析:虚拟机将常量池内的符号引用替换为直接引用的过程(符号引用比如我现在import java.util.ArrayList这就算符号引用,直接引用就是指针或者对象地址,注意引用对象一定是在内存进行)

2.1.3 初始化

初始化其实就是执行类构造器方法的()的过程,而且要保证执行前父类的()方法执行完毕。这个方法由编译器收集,顺序执行所有类变量(static修饰的成员变量)显式初始化和静态代码块中语句。此时准备阶段时的那个 static int a 由默认初始化的0变成了显式初始化的3。 由于执行顺序缘故,初始化阶段类变量如果在静态代码块中又进行了更改,会覆盖类变量的显式初始化,最终值会为静态代码块中的赋值。

注意:字节码文件中初始化方法有两种,非静态资源初始化的和静态资源初始化的,类构造器方法()不同于类的构造器,这些方法都是字节码文件中只能给JVM识别的特殊方法。

2.1.4 卸载

GC将无用对象从内存中卸载

2.2 类加载器的加载顺序

加载一个Class类的顺序也是有优先级的,类加载器从最底层开始往上的顺序是这样的

  1. BootStrap ClassLoader:rt.jar
  2. Extension ClassLoader: 加载扩展的jar包
  3. App ClassLoader:指定的classpath下面的jar包
  4. Custom ClassLoader:自定义的类加载器

栈内存,主管程序的运行,生命周期和线程同步;线程结束,栈内存也就释放,对于栈来说不存在垃圾回收问题,一旦线程结束,栈就over

栈:八大基本类型+对象引用+实列的方法

heap 堆,一个jvm只有一个堆内存,堆内存的大小是可以调节的。

类加载器读取类文件以后, 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存 hotspot-heap-structure

GC垃圾回收主要是在新生区和养老区

新生区:

  1. 类:诞生和成长的地方,甚至死亡
  2. 伊甸园,所有对象都是在伊甸园区new出来的
  3. 幸存区0,1

基本上99%的对象都是临时对象

永久区

这个区域常驻内存的,用来存放jdk自身携带的Class对象,Interface元数据,存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭vm虚拟机就会释放这个区域的内存~

一个启动类,加载了大量的第三方jar包,tomcat部署太多应用

jdk1.6以前:永久代,常量池在方法区

jdk1.7: 永久代,但是慢慢退化,去永久代,常量池在堆中

jdk1.8之后:无永久代,常量池在元空间

1661218025676

jdk1.8之后

1661907607060

OOM:

​ 原因:堆内存空间满

​ 1,尝试扩大堆内存查看结果

​ 2.分析内vu你,看一下什么地方出问题

-Xms 设置初始化内存大小

-Xmx 设置最大分配内存

-XX:+PrintGcDetails 打印GC垃圾回收信息

-XX:+DumpOutOfMemoryError dump OOM信息

JVM在进行GC时,并不是对三个区域统一回收,大部分时候,回收都是新生代

  1. 新生代
  2. 幸存区
  3. 老年代

GC的两种类:轻GC(普通GC),重GC(全局GC)

常见面试题

JVM内存模型(包括每个区存放什么)

img

堆内存模型(Eden from to 老年代),说说他们的特点

JVM如何识别垃圾

引用计数法

在这里插入图片描述
特点:每个对象都有一个引用计数器,每当对象被引用一次,计数器就+1,如果引用失效,则计数器-1,如果为0,则GC可以清理;
缺点:

  • 计数器维护麻烦!
  • 循环引用无法处理!

可达性算法
可达性算法的原理是以一系列叫做 GC Root 的对象为起点出发,引出它们指向的下一个节点,再以下个节点为起点,引出此节点指向的下一个结点,这样通过 GC Root 串成的一条线就叫引用链,直到所有的结点都遍历完毕,如果相关对象不在任意一个以 GC Root 为起点的引用链中,则这些对象会被判断为垃圾,会被 GC 回收。

img

posted @ 2023-01-05 10:00  Z_WINTER  阅读(62)  评论(0)    收藏  举报