【JavaEE】JVM中内存区域划分和类加载机制详解

一.初步了解JVM的基本

  • JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。是运行Java代码的核心部分,主要负责将Java字节码翻译为机器语言,并且提供了运行时的环境。JVM作为Java平台的一部分,隐藏了操作系统和硬件的差异性,使Java代码可以在不同的系统上运行而无需修改。换句话解释就是Java是一种半编译-半解释的语言, 当我们编写和发布一个Java程序的时候,其实只要发布.class问价即可, 当JVM拿到.class文件的时候, 就知道该如何转换. 不同平台的jvm是存在差异的,不是同一个, 但是对Java层面上提供的内容是一致的, 当Windows上的jvm拿到.class文件就可以转化为Windows上能支持的可执行指令了; Linux上的jvm就可以转化成Linux上支持的可执行指令了

  • 常见的虚拟机:JVM、VMwave、Virtual Box。
    JVM 和其他两个虚拟机的区别:

  1. VMwave与VirtualBox是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器;
  2. JVM则是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进行了裁剪。JVM 是一台被定制过的现实当中不存在的计算机。

二.JVM中的内存区域划分.

什么叫做区域划分?

JVM本质上也是一个进程,他与需要从操作系统这里申请内存.申请到的这些内存空间,就支撑后续Java程序的执行.比如说,在Java中定义变量(就需要申请空间), 申请的空间就是从JVM刚申请的空间中的一部分 换句话说,JVM在这个过程中扮演了一个"二房东"的角色. 因此JVM申请的空间就需要合理的分配利用, 这样根据实际的用途来划分出的不同空间,这个过程就叫做内存区域划分.
在这里插入图片描述

  • 堆(Heap):堆是JVM中最大的一块内存区域,几乎所有的对象实例都在这里分配内存。它是线程共享的,意味着所有线程都可以访问这个区域。堆也是垃圾回收发生的主要场所,JVM通过不同的垃圾回收算法管理堆内存,以优化内存的使用和回收不再使用的对象。可以通过启动参数如-Xmx来设置堆的最大大小。代码中new出来的对象/对象中的非静态成员变量,都是在这里
  • 虚拟机栈/本地方法栈 :每个线程都有自己的虚拟机栈,用于存储局部变量、方法参数和调用上下文等。每当一个方法被调用时,一个新的栈帧就会被压入到调用线程的栈中。栈帧包含了方法的局部变量表、操作数栈等信息。当方法执行完毕,对应的栈帧就会被弹出。虚拟机栈是线程私有的,随线程而生,随线程而灭.换句话说就是主要的功能就是记录方法之间的调用关系
  • 程序计数器(Program Counter Register):程序计数器是一个较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器通过改变程序计数器的值来选择下一条需要执行的字节码指令。程序计数器也是线程私有的,生命周期与线程紧密相关。每个线程都有一个独立的程序计数器,用于记录该线程当前正在执行的那条字节码指令。这个区域空间比较小,是用来专门存储下一条要执行Java指令的地址
  • 元数据区:也叫做方法区 , 方法区是JVM中用于存储被加载类的元数据信息的地方,包括类的结构信息、运行时常量池、字段信息、方法信息等。在Java 8及以后的版本中,方法区被实现为元空间(Metaspace),使用的是进程的本地内存而非堆内存。这部分内存是由JVM自动管理的,主要用于加载类的信息。例如:咱们写的Java代码中,if, while, for 等各种逻辑运算 这些操作都会被转换成Java字节码, 这些字节码在程序运行的时候,就会被JVM加载到内存中,放到元数据区(方法区)当中,此时,当程序要如何执行,要做哪些事,就会按照元数据区里记录的代码以此执行.

注:

  • [在这些内存区域划分之中, 堆和元数据区只有一份, 程序计数器和栈可能有多个, 因为每个线程都需要有自己的程序计数器和栈(每个线程都要有自己的执行流)]
  • 由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时刻,一个处理器(多核处理器则指的是⼀个内核)都只会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响,独立存储。我们就把类似这类区域称之为"线程私有"的内存。

三.JVM中的类加载机制.

  • JVM(Java虚拟机)的类加载机制是一个复杂而精密的过程,类加载指的是Java进程运行的时候, 需要把.class文件从硬盘读取到内存,并进行一系列解析的过程
类加载可以分为5个步骤(也可以说是3个,这个情况是把2.3.4合并成一个了)
  • 1.加载. 这个步骤主要是把硬盘上的.class文件,找到并打开文件,读取到文件中的内容(此时的内容认为读到的是二进制的数据)
  • 2.验证. 这个步骤主要是需要确保读到的内容,是合法的.class文件(字节码文件)格式
    验证过程主要包含四个验证过程:
    1. 文件格式验证
      四个验证过程中,只有格式验证是建立在二进制字节流的基础上的。格式验证就是对文件是否是0xCAFEBABE开头、class文件版本等信息进行验证,确保其符合JVM虚拟机规范。
    2. 元数据验证
      元数据验证是对源码语义分析的过程,验证的是子类继承的父类是否是final类;如果这个类的父类是抽象类,是否实现了起父类或接口中要求实现的所有方法;子父类中的字段、方法是否产生冲突等,这个过程把类、字段和方法看做组成类的一个个元数据,然后根据JVM规范,对这些元数据之间的关系进行验证。所以,元数据验证阶段并未深入到方法体内。
    3. 字节码验证
      既然元数据验证并未深入到方法体内部,那么到了字节码验证过程,这一步就不可避免了。字节码主要是对方法体内部的代码的前后逻辑、关系的校验例如:字节码是否执行到了方法体以外、类型转换是否合理等。显然这是一个非常复杂的过程,无法完全保证字节码验证准确无遗漏的。而且,如果在字节码验证浪费了大量的资源,似乎也有些得不偿失 。
    4. 符号引用验证
      符号引用的验证其实是发生在符号引用向直接引用转化的过程中,而这一过程发生在解析阶段。因为都是验证,所以一并在这讲。符号引用验证做的工作主要是验证字段、类方法以及接口方法的访问权限、根据类的全限定名是否能定位到该类等
    1. 准备. 这个步骤主要是==给类对象,申请内存空间.
      此时申请到的内存空间,里面的默认值全都是0(这个阶段中,类对象里的静态成员变量的值也就相当于是0了)
    1. 解析 主要是针对类中的字符串常量进行处理,==Java虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程.
class Test{
	private String s = "hello";
}

偏移量 :偏移量是一个相对的概念,可以理解为你相对与我的位置差了多少.
符号引用:在上述的伪代码当中,可以很明确的知道,s变量中相当于保存了"hello"字符串常量的地址, 但是在文件中不存在地址这样的概念, 因此就引入了偏移量这样的概念来表示hello存储的地方,此处文件中填充给s的"hello"的偏移量就可以认为是符号引用.
直接引用: 把.class文件加载到内存中.就会先把"hello"这个字符串加载到内存中.此时"hello"就有了真实的地址了,这个使用真实地址的方式称为直接引用.

    1. 初始化. 把类对象的各个部分的属性进行赋值填充==>触发对父类的加载,初始化静态成员,执行静态代码块.

四.双亲委派模型.

  • 双亲委派模型是Java中类加载器的一种工作机制,它的核心思想是每个类加载器在尝试加载一个类时,会先委托其父加载器去执行这个任务,只有当父加载器无法完成这个任务时,子加载器才会尝试自己去加载该类。这种机制保证了Java平台的安全性和类的唯一性,防止了核心API被恶意篡改的风险。
  • Java中的类加载器默认有三个(也可以自定义类加载器):
    1. BootstrapClassLoader :主要负责标准库的目录
    2. ExtensionClassLoader :主要负责扩展库的目录(Java语法规范里面描述了标准库中应该有的功能 ,但是实现JVM的厂商/组织,也会在标准库的基础之上扩充一些额外的功能,这些额外的功能部分就可能存储到扩展库的目录里面)
    3. ApplicationClassLoader :负责查找当前项目的代码目录,以及第三方库的目录.

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

  1. 从ApplicationClassLoader 作为入口,先开始工作
  2. ApplicationClassLoader 不会立即搜素自己负责的目录,而是会把搜素的任务交给自己的父亲.
  3. 然后,代码就进入到ExtensionClassLoader 的范畴中了, ExtensionClassLoader 也不会立即搜素自己负责的目录,也是会把搜素的任务交给自己的父亲.
  4. 再然后,代码就进入到了BootstrapClassLoader 的范畴之中了 ,BootstrapClassLoader 也不会立即搜素自己负责的目录,也是会把搜素的任务交给自己的父亲.
  5. 但是BootstrapClassLoader 发现自己==没有父亲,才会真正搜素负责的目录(标准库目录) ==.通过全限定类名,尝试在标准库目录中找到符合要求的.class文件. 如果找到了,接下来就直接进入到打开文件/读取文件等流程中; 如果没有找到,回到孩子这一辈的类加载器中,继续尝试加载.
  6. ExtensionClassLoader 收到父亲交回给他的任务之后,会进行搜素自己负责的目录,如果找到了,继续执行后面的流程; 如果没找到,就继续返回到孩子这一辈的类加载器中继续尝试加载
  7. ApplicationClassLoader 收到父亲交回给他的任务之后,也会进行搜索自己负责的目录,如果找到了,就继续执行后面的流程; 如果没找到,也是继续返回到孩子这一辈的类加载器中继续尝试加载,但是由于默认的情况下,ApplicationClassLoader 没有孩子了,此时就说明类加载失败了,就会抛出ClassNotFoundException异常.
    在这里插入图片描述
  • 上述的类加载器,存在的父子关系(不是面向对象中的,父类子类的关系) 而是类似于"二叉树", 有一个指针(引用)parent ,指向自己的"父"类加载器.
  • 上述双亲委派模型的执行过程, 可以有效的避免你自己写的类,不小心和标准库中的类名重复,导致标准库的类功能失效

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665127.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《SpringBoot3+Vue3实战》系列文章目录

前后端分离(Frontend-Backend Separation)是一种软件架构设计模式,它将传统的Web应用中的前端(用户界面)和后端(服务器逻辑和数据存储)从应用层面进行解耦,使得两者可以独立地开发、…

HTTP --tcp

TCP TCP连接 tcp/ip是全球计算机以及网络设备都在使用的一种常见的分组交换网络分层协议集,客户端可以打开一条tcp/ip连接,连接到可能运行在世界各地的服务器应用程序,一旦连接建立起来了,在客户端和服务器的计算机之间交换的报…

部署Envoy

Envoy常用术语 envoy文档官网 Life of a Request — envoy 1.31.0-dev-e543e1 documentationhttps://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request#terminology 基础总结 (1)Envoy Envoy自己本身是工作在L7层的一个proxy&#xff…

知了汇智携手川农大,为计算机学子打造实战型综合项目实训

随着数字化产业的迅猛发展和产业数字化转型的不断深入,产业对数字人才的需求也在发生变化。为了培养适应市场需求的高素质应用型人才,5月24日,知了汇智携手四川农业大学,为信息工程学院计算机科学与技术专业22级学子带来一场兼具实…

NV link

NV link比PCIe有什么厉害的地方 NV link是并行总线 NV link是去CPU中心化的 NV link只针对GPU 实际上,PCIe依然会和NV link一起使用

2024年大屏幕互动源码+动态背景图和配乐素材+搭建教程

2024年大屏幕互动源码动态背景图和配乐素材搭建教程 php宝塔搭建部署活动现场大屏幕互动系统php源码 运行环境:PHPMYSQL 下载源码地址:极速云

【c++入门】this指针

this指针引出: 我们知道一个类可以有多个实例化对象,但是这多个实例化对象所调用的成员函数是在公共代码区; 我们先来定义一个Date类: class Date { public:void init(int year, int month, int day){_year year;_month month;…

在Ubuntu乌班图上安装Docker

最近在学习乌班图相关的内容,找了一些文档安装的都是报错的,于是记录一下学习过程,希望也能帮助有缘人,首先查看乌班图的系统版本,我的是如下的: cat /proc/version以下是在Ubuntu 20.04版本上安装Docker。…

excel怎么对非数字求和汇总?

如:学生小王的成绩为:A,A,A,A,B,B-……想得到的成绩汇总求和为:2A,2A,1B,1B- 如果在低版本里,用公式计算可能相当复杂,但是有了TEXTJOIN函数和UNIQUE函数&…

【Linux系列】深入解析 `kill` 命令:Linux 下的进程管理利器

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

JDK JRE JVM 三者的关系

总结: 1. jdk 中 的 javac 编译器将 .java 文件编译为 .class 字节码文件 (编译) 2. jre 执行 .class 字节码文件 (运行) 3. jre 通过 jvm 运行程序,确保程序能够在不同平台上正确执行(实现跨平…

一文学懂Base64编码原理

前言 Base64编码与ASCII编码一样,也是一种编码方式。不同的是ASCII码采用7位二进制数表示(包括大小写字母、数字、标点符号和一些不可见字符),而Base64采用6位二进制数表示(包括大小写字母、0~9数字、和/)…

越洗越黑”的Pandas数据清洗

引言 先来一个脑筋急转弯活跃一下枯燥工作日常,问:“什么东西越洗越黑?” 有没有猜到的?猜不到我告诉你吧! 答案是“煤球”。那么这个脑机急转弯跟我们要讨论的话题有没有关系呢? 嗯是的,还是沾…

CUDA学习(1)

(一)CUDA简介 CUDA,全称Compute Unified Device Architecture,是由NVIDIA公司开发的一种计算平台和编程模型。它允许软件开发者和程序员使用NVIDIA的图形处理单元(GPU)来进行非常复杂的计算任务。简单来说,CUDA让普通…

安全风险 - 检测设备是否为模拟器

在很多安全机构的检测中,关于模拟器的运行环境一般也会做监听处理,有的可能允许执行但是会提示用户,有的可能直接禁止在模拟器上运行我方APP 如何判断当前 app 是运行在Android真机,还是运行在模拟器? 可能做 Framework 的朋友思…

DKTCDR:Domain-Oriented Knowledge Transfer for Cross-Domain Recommendation

Domain-Oriented Knowledge Transfer for Cross-Domain Recommendation IEEE(CCF B.SCI 1)-Guoshuai Zhao, Xiaolong Zhang, Hao Tang, Jialie Shen, and Xueming Qian-2024 思路 在CDR中,构建连接两个域的桥梁是实现跨域推荐的基础。然而现在的CDR方法往往在连接两个域时忽…

Usage - hackthebox

简介 靶场:hackmyvm 靶机:Usage(10.10.11.18) 难度:Easy 靶机链接:https://app.hackthebox.com/machines/Usage 攻击机1:ubuntu22.04 (10.10.16.21) 攻击机2:windows11(10.10.14.33) 扫描 nmap起手 nmap -sT …

身份认证与口令攻击

身份认证与口令攻击 身份认证身份认证的五种方式口令认证静态口令动态口令(一次性口令)动态口令分类 密码学认证一次性口令认证S/KEY协议改进的S/KEY协议 其于共享密钥的认证 口令行为规律和口令猜测口令规律口令猜测 口令破解操作系统口令破解Windows密码存储机制Windows密码破…

整合框架(spring...) 统一异常处理

1、 我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理。 附加:创建封装错误状态码和错误消息VO 代码如下: Result import io.swagger.v3.oas.annotations.media.Schema; impo…

数组的应用-24点游戏

目录 24点游戏 游戏规则 游戏主要分为三部分 电脑出牌 用户输入算式 电脑判断胜负 总结 24点游戏 游戏规则: 54张扑克抽出大小王,剩余52张用来用于游戏;每一轮从52张牌中随机抽出4张;玩家运用加,减&#xff0…