当前位置: 首页 > article >正文

JVM基础概念作用类加载运行时数据区执行引擎本地方法

JVM的一些基础概念

目录如下

  • JVM的一些基础概念
    • JVM概念
      • JVM的作用
    • JVM的构成部分
  • JVM类加载
    • 类加载过程
      • 加载
      • 链接
      • 初始化
      • 类加载器(加载类的实现者)
        • 引导类加载器
        • 拓展类加载器
        • 应用程序类加载器
        • 双亲委派机制
  • 运行时数据区
    • 程序计数器
      • 特点:
    • Java虚拟机栈
      • 栈的特点(后进先出)
    • 本地方法栈
  • Java堆内存
      • 堆的概念和作用
      • 堆内存区域分布
        • 分区原因
      • 对象在堆空间中分配的过程
        • 堆空间的参数设置
  • 方法区
    • 方法区的概念与作用
      • 方法区的大小设置
    • 方法区的垃圾回收
  • 本地方法接口
      • 概念
      • 什么是本地方法
      • 为什么要用本地方法
  • 执行引擎
    • 作用
      • 两次编译
    • 解释器与编译器
      • 解释器
      • 编译器
    • 为什么区分设计解释器和编译器

JVM概念

JVM是Java虚拟机(Java Virtual Machine)的缩写,是Java程序运行的基础

JVM负责加载字节码文件、管理内存、执行字节码指令、处理垃圾回收等工作。

JVM的作用

负责把字节码装载到虚拟机内部,把字节码转为机器码执行

JVM不仅可以执行java字节码文件,还可以执行其他语言编译后的字节码文件,是一个跨语音的平台

在这里插入图片描述

JVM的构成部分

1.类加载器(ClassLoader)

2.运行时数据区(Runtime Data Area)

3.执行引擎(Execution Engine)

4.本地库接口(Native interface)

请添加图片描述

程序在执行之前需要先将java代码转换成字节码(class文件)

JVM首先要将字节码通过类加载器(ClassLoader)将文件加载到内存中的运行数据区(Runtime Data Area)

字节码文件是JVM的一套指令规范,无法直接通过底层操作系统执行,因此需要特定的命令解析器,**执行引擎(Execution Engine)**将字节码翻译成底层系统的指令再交由CPU执行

翻译字节码的过程中需要调用**本地库接口(Native InterFace)**来实现整个程序的功能,本地库接口是由其他语言实现的

请添加图片描述

JVM类加载

请添加图片描述

作用:类加载系统负责把字节码文件(class文件)加载到内存中,存储在方法区中

字节码文件是模板,由模板创建n个对象

字节码文件加载到JVM中,被称为DNA元数据模板


类加载过程

在这里插入图片描述

加载

1.通过类名(地址)获取此类的二进制字节流

2.将字节流代表的存储结构转换为方法区的运行结构

3.在内存中生成Class对象,作为该类的访问入口

总结 : 使用流将硬盘上的字节码读取到内存中成为类

链接


初始化


类加载器(加载类的实现者)

类加载器可以分为使用java语言实现的和不使用java语言实现的

引导类加载器

不是用java写的,是使用c/c++编写实现的

用来加载java系统中的类,例如String之类的类,都是使用引导类加载器实现的

拓展类加载器

此加载器,由java语言实现,用于加载java8/jre/lib/ext目录下的类

应用程序类加载器

此加载器,由java语言实现,用于加载我们自己开发的程序类

双亲委派机制

当加载一个类时,.先让上级的类加载器去加载,优先加载系统中的类,知道启动类加载器,如果到达顶部的类加载器,当找到了该类则直接返回,若顶部类加载器找不到,再次向下委派,让字类类加载器去加载

在哪一级找到了,那就返回即可,如果向下找也没有找到,那么直接抛出类找不到异常ClassNotFoundException

好处:优先加载系统中的类,防止我们的类替换系统中的类

如何打破双亲委派机制?: 可以使用自定义的类加载器

运行时数据区

运行时数据区就是用来存储各种运行时产生的数据

方法区 堆 虚拟机栈 本地方法栈 程序计数器

程序计数器

程序计数器,用来记录每个线程执行的指令的位置,因为cpu要切换执行

特点:

程序计数器占用内存小,速度最快

每个线程都有自己的程序计数器,是线程私有的,生命周期与线程的生命周期一致

程序计数器存储当前正在执行的java方法的JVM指令地址

它是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域

请添加图片描述

Java虚拟机栈

栈是运行时的单位,即栈解决程序的运行问题,即程序如何执行

栈是一个运行结构,主要用来执行使用java语言写的方法

栈的特点(后进先出)

栈是线程私有的,每个线程运行,都有一个自己的栈空间

栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器

JVM直接对java栈的操作只有两个:调用方法入栈,执行结束出栈

栈中是会出现内存溢出的(递归调用越多,栈就越有可能溢出)

一个方法被调用后,在栈中称为是一个栈帧,保存局部变量,操作数栈,方法返回地址

本地方法栈

java虚拟机管理java方法的调用,本地方法栈管理本地方法的调用(native关键字修饰的方法,是由操作系统实现的方法) hashCode() read0() start0()

本地方法也是线程私有的,本地方法栈也是会出现内存溢出的问题

Java堆内存

堆的概念和作用

java中产生的对象都存储在堆空间中

堆空间是虚拟机中空间最大的一块区域,而且大小是可以调整的(运行时数据区,除了程序计数器区域不能调整,其他四个区域都可以对大小进行相应的调整)

堆空间被所有线程共享,是线程共有的

堆空间是会出现内存溢出的问题

堆空间是GC(Garbage Collection垃圾收集器)执行垃圾回收的重点区域。

堆内存区域分布

java8之后堆内存分为:

新生区 : 新生区分为Eden(伊甸园)区Survivor(幸存者)区

幸存者区分为:Survivor0(from),Survivor1(to)

老年区 : Old Gen

请添加图片描述

分区原因

将对象根据存活概率进行分区,将存活时间长的对象放到一个固定的区域

减少扫描垃圾时间以及GC频率,针对分类进行垃圾回收算法,对算法进行扬长避短

频繁回收新生代,较少回收老年代

对象在堆空间中分配的过程

1.新建的对象默认储存在Eden区

2.当垃圾回收时,把Eden中存活的对象移动到Survivor区,不再被引用的对象被垃圾回收

3.后续继续进行垃圾回收时,再把Eden区和Survivor0区中存活的区域移动到Survivor1区,每一次垃圾回收都需要保证有一个Survivor区是空闲的,减少内存碎片

4.当一个对象经历过15次垃圾回收后依然存活,那么将这个对象直接放入老年区,倘若有一个对象相对较大,则可以直接放入老年区

15次是一个默认的参数,可以通过设置-XX:MaxTenuringThreshold= 参数来调整次数,最大值为15次,因为在对象头有4bit位来记录回收次数,4bit位最多只能表示15

5.当老年代内存不足时,触发GC,会对老年代进行内存清理

6.若老年代执行了GC之后发现依然无法进行对象存储,会对堆进行GC,之后依然无法进行对象存储,就会出现OOM异常

Java.lang.OutOfMemoryError:Java heap space

堆空间的参数设置

以下是一些常用的堆空间的参数,更多的可以在官网进行查询

官网地址:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html -XX:+PrintFlagsInitial 查看所有参数的默认初始值
-Xms:初始堆空间内存
-Xmx:最大堆空间内存
-Xmn:设置新生代的大小
-XX:MaxTenuringTreshold:设置新生代垃圾的最大年龄
-XX:+PrintGCDetails 输出详细的 GC 处理日志

参数的设置也是JVM调优的一部分,根据实际使用的情况设置各参数的大小

方法区

方法区的概念与作用

方法区主要存储加载到内存中的类信息

方法区物理上与堆属于同一个空间,但是一般逻辑上进行区分称为元空间(Meta Space方法区),对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是与堆区分

请添加图片描述

方法区在JVM启动时被创建,实际物理内存空间中和Java堆区一样可以是不连续的

下图为方法区.栈,堆的交互关系
请添加图片描述

方法区的大小设置

方法区的大小可以进行设置,参数是-XX:MetaspaceSize,方法区的大小可拓展,方法区的空间一旦不足,就会触发FULL GC(整堆收集),会影响应用程序线程,一般情况下会将方法区的大小设置的尽量大

方法区是会出现内存溢出问题的

方法区是可以进行垃圾回族的

方法区的垃圾回收

方法区中的类什么时候会被卸载(方法区的垃圾回收)

1.该类及其字类的所有对象已经不存在了

2.加载该类的类加载器不存在了

3.该类的class对象不存在了

由于条件比较严苛,所以一般情况下可以认为类被加载后就不再释放了

本地方法接口

概念

用于对接调用的本地方法

什么是本地方法

被native修饰的方法就是本地方法

// new Object().hashCode();  //public native int hashCode();获取内存地址
// new FileInputStream("").read(); private native int read0()读硬盘数据
// new Thread().start(); private native void start0()把线程注册到内存中

为什么要用本地方法

与java之外的环境进行交互

java是应用层开发语言,无法直接对计算机底层进行调用操控,需要与java外部的环境进行交互,本地方法是一个接口,可以让java开发者无需了解java应用之外的繁琐细节

执行引擎

作用

可以将字节码指令解释/编译为机器码指令

两次编译

第一次编译是将.java文件编译为.class文件,此处的编译是开发阶段,与运行无关,可称为前端编译

第二次编译是运行时,在虚拟机中通过执行的引擎将字节码编译为机器码,称为后端编译

解释器与编译器

解释器

解释器采用不编译,逐行解释的执行方式

无需编译,可以实现立即的解释执行,但是效率相对较低

编译器

编译器是将字节码整体编译后执行

编译需要花费一定时间,但是编译后执行的效率高

为什么区分设计解释器和编译器

当程序启动后,解释器可以快速发挥作用,尽管它的效率较低,因为它的响应速度快,可以省去编译的时间,立即执行,

当程序启动一定时间后,编译器也会发挥更多作用,它会将一些热点代码编译后缓存起来,执行效率高,但是它需要花费一定的时间

所以将二者结合,在程序开始时使用解释器执行,等编译器编译完成后采用编译执行


http://www.kler.cn/a/568335.html

相关文章:

  • 5G学习笔记之BWP
  • 【Java基础】Java 中 的`final` 关键字
  • 【计算机网络入门】初学计算机网络(六)
  • 车载电源管理新标杆NCV8460ADR2G 在汽车电子负载开关中的应用
  • 基于STM32单片机物联网智能浇花系统设计
  • 请解释 Node.js 中的网络模块(http、https),如何创建 HTTP服务器?
  • 基于微信小程序的疫情互助平台(源码+lw+部署文档+讲解),源码可白嫖!
  • HTMLS基本结构及标签
  • 【星云 Orbit-F4 开发板】06. 串口密码:USART 数据传递
  • 未来该如何选择编程语言?
  • Q-Former 的设计与应用
  • 在线抽奖系统——项目测试
  • [3/11]C#性能优化-实现 IDisposable 接口-每个细节都有示例代码
  • 自然语言处理:第九十三章 大模型解码参数详解beam search/top-k/top-p/温度系数(转载
  • Pycharm使用matplotlib出现的问题(1、不能弹出图表 2、图表标题中文不显示)
  • 【洛谷贪心算法】P1106删数问题
  • 数据集笔记:新加坡LTA MRT 车站出口、路灯 等位置数据集
  • 2025前端技能
  • Python正则
  • RocketMQ的运行架构