首页 > 其他分享 >JVM必备知识

JVM必备知识

时间:2024-09-04 22:54:24浏览次数:5  
标签:必备 知识 线程 内存 JVM 执行 ClassLoader 加载

目录

一:JVM由哪些部分组成,运行流程是怎么样的

二:什么是程序计数器 

三:Java的堆是啥 

四:元空间是啥 

五:方法区是啥 

六:堆栈有什么区别

七:什么是类加载器

八:类加载器有哪些类型

九:类加载的过程

9.1:加载阶段

9.2:验证阶段

9.3:准备阶段

9.4:解析阶段

9.5:初始化阶段


前言:有关JVM其他的知识可以看我之前写的文章JVM相关知识

一:JVM由哪些部分组成,运行流程是怎么样的


由上图可以看出,JVM的组成部分由以下四部分组成:

  • ClassLoader(类加载器)

  • Runtime Data Area(运行时数据区,内存分区)

  • Execution Engine(执行引擎)

  • Native Method Library(本地库接口)

而JVM的运行流程如下:
 

(1)类加载器(ClassLoader)把Java代码转换为字节码
 

(2)运行时数据区(Runtime Data Area)把字节码加载到内存中,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层系统去执行,而是有执行引擎运行
 

(3)执行引擎(Execution Engine)将字节码翻译为底层系统指令,再交由CPU执行去执行,此时需要调用其他语言的本地库接口(Native Method Library)来实现整个程序的功能。

二:什么是程序计数器 

程序计数器:线程私有的,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址。

java虚拟机对于多线程是通过线程轮流切换并且分配线程执行时间。在任何的一个时间点上,一个处理器只会处理执行一个线程,如果当前被执行的这个线程它所分配的执行时间用完了【挂起】。处理器会切换到另外的一个线程上来进行执行。并且这个线程的执行时间用完了,接着处理器就会又来执行被挂起的这个线程。

那么现在有一个问题就是,当前处理器如何能够知道,对于这个被挂起的线程,它上一次执行到了哪里?那么这时就需要从程序计数器中来回去到当前的这个线程他上一次执行的行号,然后接着继续向下执行。

程序计数器是JVM规范中唯一一个没有规定出现OOM的区域,所以这个空间也不会进行GC

三:Java的堆是啥 

线程共享的区域:主要用来保存对象实例,数组等,当堆中没有内存空间可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。Java8的内存结构图图下

 

  • 年轻代被划分为三部分,Eden区和两个大小严格相同的Survivor区,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到老年代区间。

  • 老年代主要保存生命周期长的对象,一般是一些老的对象

  • 元空间保存的类信息、静态变量、常量、编译后的代码
    为了避免方法区出现OOM,所以在java8中将堆上的方法区【永久代】给移动到了本地内存上,重新开辟了一块空间,叫做元空间。那么现在就可以避免掉OOM的出现了。

四:元空间是啥 

在 HotSpot JVM 中,永久代( ≈ 方法区)中用于存放类和方法的元数据以及常量池,比如Class 和 Method。每当一个类初次被加载的时候,它的元数据都会放到永久代中。

永久代是有大小限制的,因此如果加载的类太多,很有可能导致永久代内存溢出,即OutOfMemoryError,为此不得不对虚拟机做调优。

那么,Java 8 中 PermGen 为什么被移出 HotSpot JVM 了?

官网给出了解释:JEP 122: Remove the Permanent Generation
 

1)由于 PermGen 内存经常会溢出,引发OutOfMemoryError,因此 JVM 的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的 OOM。

2)移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。

准确来说,Perm 区中的字符串常量池被移到了堆内存中是在 Java7 之后,Java 8 时,PermGen 被元空间代替,其他内容比如类元信息、字段、静态属性、方法、常量等都移动到元空间区。比如 java/lang/Object 类元信息、静态属性 System.out、整型常量等。

元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

五:方法区是啥 

  • 方法区(Method Area)是各个线程共享的内存区域

  • 主要存储类的信息、运行时常量池

  • 虚拟机启动的时候创建,关闭虚拟机时释放

  • 如果方法区域中的内存无法满足分配请求,则会抛出OutOfMemoryError: Metaspace


六:堆栈有什么区别

1、栈内存一般会用来存储局部变量和方法调用,但堆内存是用来存储Java对象和数组的的。堆会GC垃圾回收,而栈不会。
 

2、栈内存是线程私有的,而堆内存是线程共有的。
 

3,、两者异常错误不同,但如果栈内存或者堆内存不足都会抛出异常。

栈空间不足:java.lang.StackOverFlowError。

堆空间不足:java.lang.OutOfMemoryError。

七:什么是类加载器

 一个类的加载过程如下:

  • 类加载器:JVM只会运行二进制文件,而类加载器(ClassLoader)的主要作用就是将字节码文件加载到JVM中,从而让Java程序能够启动起来。现有的类加载器基本上都是java.lang.ClassLoader的子类,该类的只要职责就是用于将指定的类找到或生成对应的字节码文件,同时类加载器还会负责加载程序所需要的资源

  • 运行时数据区:用于分配存储空间

  • 执行引擎:执行字节码文件或本地方法

  • 垃圾回收器:用于对JVM中的垃圾内容进行回收

八:类加载器有哪些类型

类加载器通常有四种类型:

  • 启动类加载器(BootStrap ClassLoader):

    该类并不继承ClassLoader类,其是由C++编写实现。用于加载JAVA_HOME/jre/lib目录下的类库。

  • 扩展类加载器(ExtClassLoader):

    该类是ClassLoader的子类,主要加载JAVA_HOME/jre/lib/ext目录中的类库。

  • 应用类加载器(AppClassLoader):

    该类是ClassLoader的子类,主要用于加载classPath下的类,也就是加载开发者自己编写的Java类。

  • 自定义类加载器:

    开发者自定义类继承ClassLoader,实现自定义类加载规则。

而启动类加载器,扩展类加载器,应用程序类加载器,自定义类加载器又有以下几种关系

九:类加载的过程

类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)。

9.1:加载阶段

  • 通过类的全名,获取类的二进制数据流。

  • 解析类的二进制数据流为方法区内的数据结构(Java类模型)

  • 创建java.lang.Class类的实例,表示该类型。作为方法区这个类的各种数据的访问入口

9.2:验证阶段

验证类是否符合JVM规范,安全性检查

(1)文件格式验证:是否符合Class文件的规范 (2)元数据验证 这个类是否有父类(除了Object这个类之外,其余的类都应该有父类) 这个类是否继承(extends)了被final修饰过的类(被final修饰过的类表示类不能被继承) 类中的字段、方法是否与父类产生矛盾。(被final修饰过的方法或字段是不能覆盖的) (3)字节码验证 主要的目的是通过对数据流和控制流的分析,确定程序语义是合法的、符合逻辑的。 (4)符号引用验证:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量

9.3:准备阶段

为类变量分配内存并设置类变量初始值

  • static变量,分配空间在准备阶段完成(设置默认值),赋值在初始化阶段完成

  • static变量是final的基本类型,以及字符串常量,值已确定,赋值在准备阶段完成

  • static变量是final的引用类型,那么赋值也会在初始化阶段完成

9.4:解析阶段

把类中的符号引用转换为直接引用

比如:方法中调用了其他方法,方法名可以理解为符号引用,而直接引用就是使用指针直接指向方法。

 

9.5:初始化阶段

对类的静态变量,静态代码块执行初始化操作

  • 如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。

  • 如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。

标签:必备,知识,线程,内存,JVM,执行,ClassLoader,加载
From: https://blog.csdn.net/2301_76613040/article/details/141904279

相关文章

  • Python基础知识-8(PyQt GUI开发,输出乱码处理)
    (目录)介绍一个VSCode轻量级RestAPI客户端插件:ThunderClient一、关于shebang明确指定解释器#!/usr/bin/python3在shell中寻找第一个python解释器#!/usr/bin/envpython3二、Python类的私有方法/属性Python不支持私有方法/属性,但可以将类成员方法/属性名定义为......
  • java基础知识-JVM知识详解
    一、JVM内存结构Java虚拟机(JVM)的内存结构主要分为几个不同的区域,每个区域都有其特定的目的和功能。以下是JVM内存结构的主要组成部分:先看一下总体的结构图程序计数器(ProgramCounterRegister)这是一个较小的内存块,用于存储当前线程所执行的字节码指令的地址。每......
  • 使用AI写WebSocket知识是一种怎么样的体验?
    一、WebSocket基础知识1.WebSocket概念1.1为什么会出现WebSocket一般的Http请求我们只有主动去请求接口,才能获取到服务器的数据。例如前后端分离的开发场景,自嘲为切图仔的前端大佬找你要一个配置信息的接口,我们后端开发三下两下开发出一个RESTful架构风格的API接口,只有当......
  • [JVM]双亲委派
    什么是双亲委派机制首先,我们知道,虚拟机在加载类的过程中需要使用类加载器进行加载,而在Java中,类加载器有很多,那么当JVM想要加载一个.class文件的时候,到底应该由哪个类加载器加载呢?这就不得不提到"双亲委派机制"。首先,我们需要知道的是,Java语言系统中支持以下4种类加载器:Bootst......
  • 【大模型】使用 Xinference 部署本地模型,从GPU服务器到本地知识库搭建Dify【LLM大语言
    基本介绍基础信息GPU服务器获取基础安装基础信息安装显卡驱动配置显卡检查下载禁用nouveau系统自带驱动显卡驱动安装安装nvidia-docker下载配置验证Xinference部署docker部署官方文档模型下载glm-4-9b-chatEmbedding(向量)模型Rerank模型模型部署Embedding(向量)模型......
  • 【为项目做准备】Linux网络编程重点知识(项目通用知识)
    Linux网络编程的简单梳理,不够再来更新~socket()setsockopt()bind()listen()accept()socket()socket()函数,用来创建套字节头文件:#include<sys/socket.h>函数:intsocket(intdomain,inttype,intprotocol)相应参数说明:-domain:指定套接字的地址族,常见的AF_INET......
  • 这个桌面插件真的酷!该有的都有了!改造桌面必备神器
    这个桌面插件真的酷!该有的都有了!改造桌面必备神器。一个好用的桌面插件可以给我们提供很多的方便,给自己桌面打扮一下,定制一个自己喜欢的桌面插件,让桌面变得更美观实用!如何给桌面添加一个实用的插件?跟着小编一起来看下:首先,可以通过互联网找到“芝麻桌面美化”,然后下载安装......
  • 【分立元件】电阻的基础知识
            电阻与电容、电感一样都是最基本的元器件,大量使用于各种电气或电子设备中。对从事电气工作的人而言或许过于普通,平时忽视了它,但如果没有电阻,电气或电子电路就无法建立。电阻就是如此重要的元器件。 电阻的原理        电阻的数值取决于电阻材料的电......
  • 从初识Redis到精通Redis,一份Java程序员必备Redis实战文档分享
    本文深入浅出的介绍了Redis的五种数据类型,并通过多个实用示例展示了Redis的用法。除此之外还讲述了Redis的优化方法和扩展方法。一共由三个部分组成,第一部分对Redis进行了介绍,说明了Redis的基本使用方法、它拥有的5种数据结构以及操作5种数据结构的命令,并详解了如何使用R......
  • JVM 垃圾回收机制:GC
    目录一、死亡对象的判断算法1.1 引用计数算法1.2 可达性分析算法二、垃圾回收算法2.1 标记-清除算法2.2 复制算法2.3 标记-整理算法2.4 分代算法三、垃圾收集器3.1 CMS收集器(老年代收集器,并发GC)3.2 G1收集器(唯一一款全区域的垃圾回收器)JVM的垃圾回收机......