JAVA虚拟机----JVM

(一)认识JVM

     JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。
    虚拟机是指通过软件模拟的具有完整硬件功能的、运⾏在⼀个完全隔离的环境中的完整计算机系统。
     常⻅的虚拟机:JVM、VMwave、Virtual Box。

(二)JVM运行流程

    程序在执行前要把java代码转为.class文件,JVM首先要将.class文件通过类加载器加载到运行时数据区,但是.class文件不可以直接给底层操作系统执行,需要特定的解析器将字节码翻译成底层系统指令再给CPU去执行,这个过程需要调用其他语言的接口---本地库接口

(三)JVM的内分划分

JVM的内存由五部分组成:

1.堆

   堆用来存储我们new出来的对象,并且堆是所有线程共享的

   堆里面分为两个区域:新生代和老生代,新生代存放新建的对象,当个经过数次GC后还存活的对象会放入老生代,具体我们会在JVM垃圾回收机制中说明  

2.栈

    栈分为两种,一种时虚拟机栈,一种是本地方法栈,栈是线程私有的,每个线程都有自己的虚拟机栈,且生命周期和线程是相同的。

    栈具体描述的是JAVA方法执行的内存模型,每个方法在执行时都会创建一个栈帧,用来存储局部变量等信息

    java虚拟机中的栈叫虚拟机栈,本地方法的栈叫本地方法栈

3.程序计数器

   程序计数器也是线程私有的,用来存放下一条指令的地址,如果当前线程正在执⾏的是⼀个Java⽅法,这个计数器记录的是正在执⾏的虚拟机字节码指令的地址;如果正在执⾏的是⼀个Native⽅法,这个计数器值为空。

4.元数据区(方法区)

用来存储虚拟机加载的类信息,常量和静态变量等数据的

JDK 1.8 元空间的变化
1. 对于 HotSpot 来说,JDK 8 元空间的内存属于本地内存,这样元空间的⼤⼩就不在受 JVM 最内
存的参数影响了,⽽是与本地内存的⼤⼩有关。
2. JDK 8 中将字符串常量池移动到了堆中。运⾏时常量池
运⾏时常量池是⽅法区的⼀部分,存放字⾯量与符号引⽤。
字⾯量 : 字符串(JDK 8 移动到堆中) 、final常量、基本数据类型的值。
符号引⽤ : 类和结构的完全限定名、字段的名称和描述符、⽅法的名称和描述符。

(四)JVM的类加载机制

对于一个类来说,我们需要经过加载->验证->准备->解析->初始化这五个步骤

接下来我们看看具体每个步骤要如何执行内容

1.加载

加载阶段是整个类加载中的一个过程,我们需要在这个阶段完成:

1)通过⼀个类的全限定名来获取定义此类的⼆进制字节流。
2)将这个字节流所代表的静态存储结构转化为⽅法区的运⾏时数据结构。
3)在内存中⽣成⼀个代表这个类的java.lang.Class对象,作为⽅法区这个类的各种数据的访问⼊。

2.验证

   我们加载阶段生成了一个.class文件,我们要确保这个.class文件是正确的,包含的信息符合我们的要求,验证就是为了确保.class文件正确性的,我们需要验证:文件格式,字节码,符号引用等。

3.准备

   准备是为类中定义的2变量分配内存并且设置类变量的初始值的,我们定义了变量在这个阶段,还没有被赋值,只有初始值,我们这时候看,就全为0

4.解析

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

5.初始化

初始化阶段,我们JVM才开始真正执行类中编写的程序代码,将主导权交给程序

双亲委派模型

自从JDK1.2以来,java就一直保持三层类加载器,双亲委派的类加载架构器

    那我们来说一下他的工作过程:如果⼀个类加载器收到了类加载的请求,它⾸先不会⾃⼰去尝试加载这个类,⽽是把这个请求委派给⽗类加载器去完成,每⼀个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当⽗加载器反馈⾃⼰⽆ 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,⼦加载器才会尝试⾃⼰去完成加载。

  由上到下我们查找的顺序是:先去标准库下查找,查找不到再去扩展库中查找,如果仍然查不到就会去第三方库或者我们自己写的方法中查找

优点:1.避免类的重复加载,如果a和b都有一个父类c,那么当a启动时就会把c加载起来,那么b类在进行加载时就不需要再重复加载c了

2.安全性:使⽤双亲委派模型也可以保证了 Java 的核⼼ API 不被篡改,如果没有使⽤双亲委派模
型,⽽是每个类加载器加载⾃⼰的话就会出现⼀些问题,⽐如我们编写⼀个称为 java.lang.Object
类的话,那么程序运⾏的时候,系统就会出现多个不同的 Object 类,⽽有些 Object 类⼜是⽤⼾⾃
⼰提供的因此安全性就不能得到保证了

(五)JVM的垃圾回收

上面说程序计数器,栈的生命周期是和线程有关的,当线程结束时,内存需要跟着线程一起挥手,所以我们现在就来说一下JVM时如何进行垃圾回收的。

   Java堆中存放着⼏乎所有的对象实例,垃圾回收器在对堆进⾏垃圾回收前,⾸先要判断这些对象哪些还存活,哪些已经"死去"。判断对象是否已"死"有如下⼏种算法

如何判断对象不再需要
1)引用计数器

  就是跟名字一样,给对象加一个计数器,如果有地方引用他就会计数器+1,如果引用失效了计数器就-1,任何时刻计数器为0,就说明对象可以被挥手了

   优点:实现简单,方便理解,同时效率较高  缺点:无法解决对象循环引用(类似多线程中的死锁问题)

2)可达性分析

   我们JVM就是通过可达性分析来检测对象是否存活

   核心思想就是遍历,通过根对象作为起始点,从这结点开始向下遍历,走过的路径称为引用链,当一个对象没有任何引用链可以到达时,证明这个对象是不可用的

   比如上图中的object 5和object6 7,虽然她们之间有关联,但是无法由根对象遍历到,所以我们认为它们是不可达的,就会被判定成可回收对象

   在java中可以被当作根对象的有:

1. 虚拟机栈(栈帧中的本地变量表)中引⽤的对象;
2. ⽅法区中类静态属性引⽤的对象;
3. ⽅法区中常量引⽤的对象;
4. 本地⽅法栈中 JNI(Native⽅法)引用的对象

垃圾回收算法
1)标记-清除算法

标记清除就是标记出所有需要回收的对象,在标记完成后统一回收

但是这种算法会导致内存碎片化,也会有效率问题

内存碎片化:标记清除后会产生大量不连续的内存碎片,内存碎片过多会导致我们之后要分配一块连续的空间时,可能无法找到足够的内存

2)  复制算法

   复制算法就是对上述的标记清除算法进行优化,他是将内存分成大小相等的两块,每次只使用其中一边,当这块内存需要垃圾回收时,我们就会将这块区域仍然存活的对象复制到另一边,然后再将这里的内存区域一次性清理,这样既可以提升效率,也可以避免内存碎片化。

  但是仍然有一定的问题,这会导致我们无法充分利用我们的内存,每次都会损失一般的内存空间来复制

3)标记整理算法

    复制算法在面对对象存活率较高的情况下,每次都需要复制很多对象,效率也不会很高,所以在面对对象存活率较高时,我们可以是以哦那个标记整理算法,在刚开始标记无用对象时与标记清除一直,但是之后我们却不是直接删除,而是让所有存活的对象向一端移动,再清理掉边界以外的内存即可

但同时,如果存活元素过多也会有效率问题

4)分代算法

   分代算法是通过区域划分:新生代和老年代,实现不同区域不同策略的垃圾回收机制(当前我们的JVM都是使用分代算法解决垃圾回收机制)。

   新生代中,每次垃圾回收都会有很多对象死去,只有少量存活,我们才用复制算法,而老年代存活对象较多,我们可以采用标记整理或者标记清理算法。

   那什么对象是新生代,什么对象是老年代?

   • 新⽣代(Minor GC):⼀般创建的对象都会进⼊新⽣代;
   • ⽼年代(Full GC):对象经历了 N 次(⼀般情况默认是 15 次)垃圾回收依然存活下来的对象会从新⽣代移动到⽼年代。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux进阶命令-重定向

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 经过上一章Linux日志的讲解,我们对Linux系统自带的日志服务已经有了一些了解。我们接下来将讲解一些进阶命令&am…

5、PointNeXt

5、PointNeXt PointNeXt论文:PointNeXt 关于PointNeXt实际上仅仅是在PointNet的基础上做了一些改进,从它的全称就可以看出,Revisiting PointNet with Improved Training and Scaling Strategies,在PointNet的基础上,引…

前端常用的主流框架有哪些

前端开发中,有几个主流框架非常受欢迎,它们为开发者提供了丰富的功能和高效的开发体验。以下是一些当前最常用的前端主流框架: React: React 是由 Facebook 开发的一个用于构建用户界面的 JavaScript 库。它鼓励使用组件化的开发模…

O1-preview:智能预测与预取驱动的性能优化处理器设计OPEN AI

# 创作不易,您的打赏、关注、点赞、收藏和转发是我坚持下去的动力! O1-preview 是一种用于性能优化的处理器设计原理,主要通过智能预测和数据预取来提升处理器的执行效率。以下是对 O1-preview 原理的详细介绍,以及它相对于以往的…

微波无源器件 功分器 4 一种用于天线阵列的紧凑宽带四路双极化波导功分器

摘要: 一种新型紧凑和高效率,在一个同相2x4方案(四路)显示双极化的功分器的设计和仿真被提出了,两个基本的正交模式TE10和TE01在四个方波导处同相输出通过使用四个3端口个四个E面和两个H面功分结构。此功分末端接了两个商用波导(WR75)端口&am…

插入排序详解

思路 把后面的值(temp)与前面的值(end)做对比, 若temp位置的值小于end位置的值, end位置的值给end1位置。。 语言难以描述,请大家看下图。 代码 void InsertSort(int *arr, int n) {/*为了…

django开发流程

一、官方网站: Django documentation | Django documentation | Djangohttps://docs.djangoproject.com/en/5.1/ 1.安装 django : pip install django 2. django项目的配置文件 (settings.py) BASE_DIR 项目根路径 DEBUG 调试模式 INSTALLE…

旷视轻量化网络shufflenet算法解读

目录 预备知识 1. 回顾MobileNet V1的核心思想---深度可分离卷积 2.ShuffleNet主要有两个创新点 2.1 分组卷积与11分组卷积 2.2 channel Shuffle(通道重排) 2.3 通道重排过程 3. ShuffleNet网络结构 3.1 ShuffleNet unit 3.2 不同分组数的Shu…

AlexNet项目图片分类通用模型代码

目录 一:建立AlexNet模型(在model文件中写) 1.构造5层卷积层 2.构造3层神经网络层 3.forward函数 4.模型最终代码 二:训练数据(在train中写) 1.读出数据 2.训练 3. 测试模型更新参数 4.完整的训练…

问题——IMX6UL的uboot无法ping主机或Ubuntu

主要描述可能的方向,不涉具体过程,详细操作可以查阅网上相关教程 跟随正点原子教程测试以太网端口时,即便按照步骤多次尝试也无法ping通,后补充了些许网络工程基础知识解决了这个问题。 uboot无法ping主机或Ubuntu有多种可能&…

Redis集群知识及实战

1. 为什么使用集群 在哨兵模式中,仍然只有一个Master节点。当并发写请求较大时,哨兵模式并不能缓解写压力。我们知道只有主节点才具有写能力,那如果在一个集群中,能够配置多个主节点,是不是就可以缓解写压力了呢&…

总结拓展十:SAP开发计划(下)

第一节 接口功能开发说明书设计 1、软件系统接口作用 答:系统接口,是实现系统间数据传输的功能。 2、软件系统接口特点 1)采用Web Service技术作为平台,有众多的数据传输协议标准,通过API与外界交流数据。 2&…

Vscode搭配latex简易教程

1. 找镜像网站下载texlive的iso文件 清华源镜像 下载之后直接打开iso文件,打开install-tl-windows.bat文件,进行安装即可,安装大概30分钟左右 2. VScode端配置 2.1 下载这三个插件 2.2 打开设置 2.3 追加内容到配置json文件当中 // Latex…

14_input子系统my_touch_device,my_touch_handlerLinux内核模块

01_basicLinux内核模块_the kernel was built by:x86 64-linux-gnu-gcc-12(ub-CSDN博客文章浏览阅读678次,点赞3次,收藏3次。环境IDubuntuMakefilemodules:clean:basic.creturn 0;运行效果。_the kernel was built by:x86 64-linux-gnu-gcc-12(ubuntu 12…

贷款年利率迷局:年利率3.8%为何变成2.07%?

朋友们,聊聊贷款那点事儿,特别是那个让人又爱又恨的年利率,听起来简单,3.8%就是一年给银行3.8%的贷款总额当利息,对吧?但别急,这里头学问大着呢!有时候,你发现标着3.8%的…

keil调试变量值被篡改问题

今天遇到一个代码中变量值被篡改的问题,某个数组的第一个值运行一段时间之后变成了0,如图: 看现象基本可以断定是内存越界导致的,但是要如果定位是哪里内存越界呢? keil提供了两个工具 1、set access breakpoint at(设置访问断点…

ES6标准---【八】【学习ES6看这一篇就够了!!!】

目录 前言 export命令 输出变量 输出函数/类 export中的as别名 export必须一一对应 export接口的响应性 注意 import命令 import命令的语法 import命令里的as别名 import的只读性 import命令具有提升性 import的一些约定 import的静态执行 import的唯一执行性 模…

基于SmartUpload组件实现文件上传功能的案例

SmartUpload组件简介 SmartUpload组件 专门用于实现文件上传及下载的免费组件SmartUpload组件特点 使用简单:编写少量代码,完成上传下载功能能够控制上传内容能够控制上传文件的大小、类型缺点:目前已停止更新服务 SmartUpload组件应用 单文…

【Java】多线程前置知识 初识Thread

多线程前置知识 & 初识Thread 冯诺依曼体系结构初步认识存储设备CPU指令 操作系统初识操作系统内核态和用户态 进程/任务进程是什么进程的管理进程的调度虚拟内存地址进程间的通信 线程线程的出现线程是什么线程可能出现的问题线程与进程的联系和区别 协程初识Thread类Thre…

Java lambda表达式的变量捕获

有人看到这个lambda表达式能够访问isQuit这个变量而且还是可以被修改的变量,就发出疑问了,之前不是说lambda不能不或变量吗? 1.规则 java的lambda表达式变量捕获规则只是针对于外部作用域的局部变量来说的!!&#xf…