JVM(java虚拟机 详解三个主要的话题:1.JVM 中的内存区域划分2.JVM 的类加载机制3.JVM 中的垃圾回收算法)

jdk  java开发工具包

jre  java运行时环境

jvm java虚拟机

JDK、JRE、JVM之间的关系?
JDK(Java Development Kit):Java开发工具包,提供给Java程序员使用,包含了JRE,同时还包含了编译器javac与自带的调试工具Jconsole、jstack等。
JRE(Java Runtime Environment):Java运行时环境,包含了JVM,Java基础类库。是使用Java语言编写程序运行的所需环境。
JVM:Java虚拟机,运行Java代码

java语言的顺序:

1.使用记事本或者IDEA(集成开发环境)编写Java源程序
2.使用javac.exe编译器编译Java源程序,生成xxx.class的字节码文件 语法格式:javac xxx.java

3.使用java运行xxx.class字节码文件 语法格式:java xxx

因此, 我们编写和发布一个 java 程序,其实就只要发布 .class 文件即可jvm 拿到 .class 文件,就知道该如何转换.windows 上的 jvm 就可以把 .class 转成 windows 上能支持的可执行指令了linux 上的 jvm 就可以把 .class 转成 linux 上可以支持的可执行指令了!

三个主要的话题:

1.JVM 中的内存区域划分
2.JVM 的类加载机制
3.JVM 中的垃圾回收算法


JVM 中的内存区域划分

JVM其实也是进程

在任务管理器中可以看到

进程运行的前期,需要向系统申请一些资源(内存就是其中典型的资源)

这些内存就支撑了后续的java程序的执行.

比如:在java中定义变量所消耗的内存,就是jvm从系统中申请的内存.

jvm从系统中要了一些内存之后,又会根据实际的内存来分批不同的空间来存放不同的数据.(这个就是区域划分).

此处谈到的堆和栈和数据结构中谈到的堆和栈是不同的.

堆:

代码中new出来的对象都是在这里,对象中持有的非静态变量也在这里.

栈:

1.本地方法栈:jvm内部通过c++写的底层逻辑,调用关系和局部变量(一般不会谈到这,说到栈都是说的是栈的虚拟机栈)

2.虚拟机栈:记录了java中方法的调用关系,java代码的局部变量.

每个线程都有自己的栈和计数器

程序计数器:

这个区域比较小的空间,专门存储下一条java指令要执行的地址.(每个线程都有自己的程序计数器和栈)

元数据区(以前java中叫做方法区,从1.8开始改名字):

指的是一些有辅助性质的,描述性质的属性.

咱们写的 java 代码, if, while, for, 各种逻辑运算..这些操作最终都会被转换成 java 字节码
(javac 就会完成上述代码=>字节码)
此时这些字节码在程序运行的时候就会被jvm 加载到内存中放到 元数据区(方法区) 里头
此时,当前程序要如何执行,要做哪些事情,就会按照上述元数据区里记录的字节码依次执行了.

就类似硬盘一样


JVM的类加载机制

类加载大体的过程可以分成5 个步骤(也有资料上说是 3 个,这个情况就是把 2,3,4 合并成一个了)

1.加载

把硬盘上的.class文件找到,然后打开文件,然后读取文件内容.(认为读到的是二进制数据)

2.验证

需要验证当前内容是合法的,是.class(字节码文件)格式

3.给类对象申请空间

此处申请的内存空间.值都是默认0

4.解析

主要是针对字符串常量处理.

解析阶段是java虚拟机将常量池内的符号转换为直接引用的过程,也就是初始化常量的过程

将符号偏移量转换为直接引用hello的地址就是解析

5.初始化

还要执行静态代码块的逻辑.还可能触发父类的加载.


加载环节(双亲委派模型):描述了如何查找.class的文件策略.

JVM 中进行类加载的操作,是有一个专门的模块,称为"类加载器"(ClassLoader)JM 中的类加载器默认是有 三个 的.(也可以自定义)

上述这三个类型存在父子关系.从下到上.

双亲委派模型工作过程:
1.从 ApplicationClassLoader 作为入口,先开始工作
2.ApplicationClassLoader 不会立即搜索自己负责的目录会把搜索的任务交给自己的父亲,
3.代码就进入到 ExtensionClassLoader 范畴了ExtensionClassLoader 也不会立即搜索自己负责的目录也要把搜索的任务交给自己的父亲
代码就进入到 BootstrapClassLoader 范時了BootstrapClassLoader 也不想立即搜索自己负责的目录也要把搜索的任务交给自己的父亲
5. BootstrapClassLoader 发现自己没有父亲才会真正搜索负责的目录(标准库目录)
通过全限定类名,尝试在标准库目录中找到符合要求的 .class 文件
如果找到了,接下来就直接进入到打开文件/读文件等流程中,如果没找到,回到孩子这一辈的类加载器中,继续尝试加载,
6.ExtensionClassLoader 收到父亲交回给他的任务之后,
自己进行搜索负责目录(扩展库的目录)
如果找到了,接下来进入到后续流程.
如果没找到,也是回到孩子这一辈的类加载器中继续尝试加载,
7.ApplicationClassLoader 收到父亲交回给他的任务之后自己进行搜索负责的目录(当前项目目录/第三方库目录)
如果找到了,接下来进入后续流程.
如果没找到,也是回到孩子这一辈的类加载器中继续尝试加载.由于默认情况下 ApplicationClassLoader 没有孩子了,此时说明类加载过程失败了!就会抛出 ClassNotFoundException 异常

JVM垃圾回收机制(GC)

c++就没有这样的机制,不是因为这个机制很难实现,而是因为这个东西会额外的付出系统开销.影响程序的执行性能.

java发展多年,可以把垃圾回收处理控制在1ms内.一个请求或者接受时间一般是几ms到几十ms.

如果一个引用没有任何指向,就说明所有的指向都结束了,就是荒废的引用.就可以进行回收了.

如果代码比较复杂,这样就解决不了了,就有了以下两中办法:

1.引用计数

这种方法没有在java中使用,但是在别的语言中广泛使用(比如python,PHP等等)

给每个对象安排一个小空间,用来记录当前对象有几个引用.

2.可达性分析(JVM用的是这个)

本质上是用"时间 换 空间”相比于引用计数,需要消耗更多的额外的时间, 但是总体来说,还是可控的.
不会产生类似于"循环引用"这样的问题.
在写代码的过程中,会定义很多的变量.
比如,栈上的局部变量/方法区中的静态类型的变量/常量池中引用的对象!....
就可以从这些变量作为起点,出发,尝试去进行"遍历"所谓的遍历就是会沿着这些变量中持有的引用类型的成员,再进一步的往下进行访问...
所有能被访问到的对象,自然就不是垃圾了.剩下的遍历一圈也访问不到的对象,自然就是垃圾~~


识别出垃圾以后,还需要释放垃圾:

主要的释放方式有三种:

a.标记-清除(一般不会用这个方法,因为内存碎片问题,比较致命)

比如黑色的就是垃圾,此时我们直接释放,就会产生很多小的内存碎片,就会导致后续的内存申请失败

因为内存申请是一片连续的空间.

b.复制算法

c.标记-整理

类似于顺序表删除中间元素.(搬运)


分代回收(依据不同种类的对象,采取不同的方式)
引入概念, 对象的年龄,
JM 中有专门的线程负责周期性扫描/释放,一个对象,如果被线程扫描了一次,可达了(不是垃圾),年龄就 +1(初始年龄相当于是 0)
JVM 中就会根据对象年龄的差异,把整个堆内存分成两个大的部分新生代(年龄小的对象)/ 老年代(年龄大的对象)

1)当代码中 new 出一个新的对象,这个对象就是被创建在伊甸区的.伊甸区中就会有很多的对象
.个经验规律: 伊甸区中的对象,大部分是活不过第一轮 GC这些对象都是"朝生夕死”,生命周期非常短!!

2)第一轮 GC 扫描完成之后,少数伊甸区中幸存的对象, 就会通过复制算法, 拷贝到 生存区后续 GC 的扫描线程还会持续进行扫描,不仅要扫描伊甸区,也要扫描生存区的对象.生存区中的大部分对象也会在扫描中被标记为垃圾.少数存活的,就会继续使用复制算法,拷贝到另外一个生存区中!!只要这个对象能够在生存区中继续存活,就会被复制算法继续拷贝到另一半的生存区中.每次经历一轮 GC 的扫描,对象的年龄都会 +1

3)如果这个对象在生存区中,经过了若干轮 GC 仍然健在~~JVM 就会认为,这个对象生命周期大概率很长, 就把这个对象从生存区,拷贝到老年代~~


4)老年代的对象,当然也要被 GC 扫描,但是扫描的频次就会大大降低了
老年代的对象,要 G 早 G 了~~ 既然没 G 说明生命周期应该是很长的,频繁 GC 扫描意义也不大,白白浪费时间.不如放到老年代,降低扫描频率,


5)对象在老年代寿终正寝,此时 JM 就会按照标记整理的方式,释放内存!

Java的分代回收机制是一种垃圾回收策略,它将堆内存分为不同的代,分别是年轻代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)。

  1. 年轻代:年轻代是新创建的对象的存放区域,它又被分为Eden区和两个Survivor区(通常是一个From区和一个To区)。当对象被创建时,它们首先被分配到Eden区。当Eden区满时,会触发一次Minor GC(年轻代垃圾回收),将仍然存活的对象复制到其中一个Survivor区,同时清空Eden区和另一个Survivor区。经过多次Minor GC后,仍然存活的对象会被移到老年代。

  2. 老年代:老年代主要存放生命周期较长的对象。当老年代空间不足时,会触发一次Major GC(全局垃圾回收),对整个堆进行垃圾回收。Major GC的频率相对较低,因为老年代的对象生命周期较长。

  3. 永久代:永久代主要用于存放类的元数据、常量池等信息。在Java 8及以后的版本中,永久代被元空间(Metaspace)所取代。

分代回收机制的优势在于根据对象的生命周期将堆内存划分为不同的区域,针对不同区域采用不同的垃圾回收算法,从而提高垃圾回收的效率。年轻代中的Minor GC频繁进行,可以快速回收短生命周期的对象,而老年代中的Major GC相对较少,减少了全局垃圾回收的开销。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在AI工业变革的拐点,迎来AI智算“安卓时刻”

今天,我们正在进入AI的工业变革拐点期。所谓AI的工业变革,主要指以大模型AI所引发的通用AI和以通用AI为目标构建的工业标准化AI智算基础设施。 在通用计算时代,X86所代表的工业标准化技术体系造就了企业IT、互联网与云数据中心。而在智算时代…

计网笔记:第1章 计算机网络概论

计网笔记:第1章 计算机网络概论 第1章 计算机网络概论1.1 计算机网络发展与分类1.2 OSI和TCP/IP参考模型OSI与TCP/IP参考模型图 1.3 数据封装与解封过程借助OSI模型理解数据传输过程(封装)借助OSI模型理解数据传输过程(解封) 1.4 本章例题 第1章 计算机网络概论 1.…

mac系统镜像源管理之nrm的安装与使用

之前有介绍过:pnpm安装和使用,nvm安装及使用,在前端开发中其实还有一个工具也会偶尔用到,那就是nrm,本文就详解介绍一下这个工具,非常的简单且好用~ 文章目录 1、什么是nrm?2、安装3…

Docker原理与基础命令

目录 一、云与虚拟化知识 (一)云基本知识 1.云基本介绍 2.常用的云服务器 3.云服务模型 3.1 IaaS 3.2 PaaS 3.3 SaaS (二)虚拟化介绍 1.什么是虚拟化 2. 虚拟化技术概述 3.虚拟化技术类型 4.虚拟化架构 ①寄居架构…

PostgreSQL中的索引类型有哪些,以及何时应选择不同类型的索引?

文章目录 索引 解决方案和示例代码 PostgreSQL提供了多种索引类型,每种类型都有其特定的应用场景和优势。选择合适的索引类型可以显著提高查询性能,减少数据库负载。 索引 以下是PostgreSQL中常见的索引类型及其适用场景: 1. B-tree 索引 …

对增加LLaMA 3 上下文长度技术的猜测

AI苏妲己: 在许多应用场景中,如长对话、长文档摘要或长期计划执行等,大语言模型能够支持较长的上下文窗口是非常理想的。以一次处理约50页书籍内容为例,通常需要模型支持32K个token的上下文长度。目前,主流的大语言模…

【题目2】 大衍数列,斐波拉契数列等,用VBA 和python解决

目录 0 原始题目:大衍数列 0.1 原始题目 0.2 知识点 1 大衍数列 1.1 大衍数列定义 1.1.1 大衍数列定义 1.1.2 大衍数列注意点 1.2 用VBA实现大衍数列 1.3 用python实现大衍数列 2 斐波拉契数列 /兔子数列/ 黄金分割数列 2.1 斐波拉契数列定义 2.1.1 下面…

【Linux】Kill Process 后依然占用显卡空间并显示 No Such Process

问题 : 如图所示,在显卡上使用 Crtl C 结束某个进程后,使用 nvitop 工具或者 nvidia-smi 命令,显示 No Such Process,但是确占用着显卡空间。搜索这个 PID 时,也显示找不到。 解决:实际上是因为…

BUUCTF——[网鼎杯 2018]Fakebook

BUUCTF——[网鼎杯 2018]Fakebook 1.测试SQl注入的注入点1 2.尝试使用-- -进行闭合,但是不行 3.尝试使用数字型的SQL注入,使用--进行注入后面的SQL语句 4.尝试使用and 11 判断其是否真的存在SQL注入 5.尝试使用and 12进行判断 6.发现这个地方确实存…

机器学习 | 使用Python开发多输出回归模型

多输出回归是监督机器学习的一种特殊形式,可以同时预测多个目标变量。虽然传统回归侧重于基于一组输入特征预测单个数值(目标变量),但多输出回归扩展了这一概念,可以同时预测多个数值,这在各种现实世界的应…

【产研测类】线上问题处理机制

1 概述 本规范致力于优化运营与产研团队在线问题管理的效率与效果,全面覆盖生产问题的识别、处理机制、分类分级、责任归属和明确奖惩机制。同时,侧重资源重点解决主流程关联的核心模块生产问题。如此,确保各个环节责任到人,内…

单细胞分析|整合 scRNA-seq 和 scATAC-seq 数据

引言 单细胞转录组学极大地提升了对细胞状态进行分类的能力,但要深入理解生物学现象,不能仅仅停留在对细胞群的简单列举上。随着新方法的不断涌现,用于测量细胞的不同状态,一个关键的挑战是如何将这些数据集整合起来,以…

Spring三级缓存源码解析

Spring三级缓存 前置知识三级缓存定义SpringBean生命周期 Bean的初始化getSingleton 分析加入一级缓存 CreateBean过程(A)A填充属性BB填充属性A,执行getSingleton(A)B完成初始化 前置知识 三级缓存定义 public class DefaultSingletonBeanRegistry ext…

云打印为什么这么便宜?

随着云打印的火热发展,越来越多的用户开始选择云打印服务了。我们在之前的内容里也介绍过,现在的易绘创云打印服务A4低至5分钱/页。那么云打印为什么这么便宜呢?今天小易就带大家来了解一下。 云打印为什么这么便宜? 相信很多用户…

Element-plus DatePicker 日期选择器【正则校验时间范围】

效果图&#xff1a; 利用element-plus中的form表单验证完成效果。 <el-form-item label"检查计划截止日期&#xff1a;" prop"deadline"><el-date-pickerv-model"form.deadline"value-format"YYYY-MM-DD"style"width: …

NAT的知识点和实现

1.NAT的作用&#xff1a; &#xff08;1&#xff09;、把内网私网IP转换公网IP&#xff1b; &#xff08;2&#xff09;、隐藏内网&#xff0c;起到保护内网作用&#xff1b; &#xff08;3&#xff09;、适当的缓解的IPv4地址空间枯竭&#xff1b; &#xff08;4&#xff…

【数据分析面试】28.查找职工信息 (SQL文字处理/通配符查找)

题目 现在公司里有职工信息表Worker, HR需要你提供不同的职工信息&#xff0c;包括&#xff1a; 从 Worker 表中获取 “FIRST_NAME” 并以大写形式显示。从 Worker 表中获取 DEPARTMENT 的唯一值。查找 Worker 表中 FIRST_NAME 的前三个字符。查找 Worker 表中名为 ‘Amitabh…

值传递和地址传递

文章目录 目录值传递地址传递 目录 值传递 package com.zhang.parameter; //值传递 public class MethodDemo1 {public static void main(String[] args) {int a 10;System.out.println(a);System.out.println("~~~~~~~~~~~~~~~");change(a);//无论你传入的是什么 …

备战Java面试

一&#xff0e;JAVA基础 1.八个基本数据类型&#xff0c;长&#xff0c;占几个字节&#xff0c;取值范围是多少。 基本类型&#xff1a; Byte 一般的数据 1个字节 取值范围 -128—127 short 极大的数据 2个字节 取值范围 -2的15次方到2的15次方减一 int 4个字节…

JS绘制电流闪烁流动效果

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>电流闪动动效</title><style>.sd1 {dis…