Java——JVM

前言

JVM.即Java虚拟机.用来解释执行Java字节码.

一、JVM中的内存区域划分

JVM其实也是一个进程,进程运行过程中,要从操作系统这里申请一些资源(内存就是其中的典型资源)

这些内存空间,就支撑了后续Java程序的执行.

JVM从系统中申请了一大块内存,这一大块内存给Java程序使用的时候,又会根据实际的使用用途来划分出不同的空间(区域划分)

1. 堆(只有一份)

代码中new出来的对象,就是在堆里的,对象中持有的非静态成员变量,也就是在堆里.

2. 栈(可能有N份)

本地方法栈/虚拟机栈->记录了Java代码的调用关系,Java代码的局部变量

包含了方法调用关系和局部变量

3. 程序计数器(可能有N份)

这个区域比较小的空间,专门用来存储吓一跳要执行的Java指令的地址.

4. 元数据区(只有一份)(以前也叫方法区)

" 元数据 " 是计算机的一个常见术语(meta data)

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

类的信息,方法的信息:

一个程序,有哪些类,每个类里有哪些方法,每个方法里面都包含了那些指令,都会记录在元数据区里.

硬盘上不仅仅要存文件的数据本体,还需要存储一些辅助信息:

文件的大小,文件的位置,文件的拥有者,文件的修改时间,文件的权限信息.....这些统称为" 元数据 "

比如这样一个代码:

class Test{private int n;private static int m;
}
main(){
Test t = new Test();
}

这个代码中:
n是Test的成员变量,是在 堆 的.

t是一个局部变量(引用类型),在 栈.

static修饰的变量,称为 " 类属性 "

static修饰的方法,称为 " 类方法 "

非static修饰的变量,称为 " 实例属性 "

非static修饰的方法,称为 ' 实例方法 "

上述带有static 修饰的变量,就是在类对象(.class)中,也就是在元数据区中.

JVM把.class文件加载到内存之后,就会把这里的信息使用对象来表示,此时这样的对象就是类对象.

类对象里就包含了一系列的信息:

包括但不限于:类的名称,类继承自哪个类,实现了哪些接口.

都有哪些属性,都叫什么名字,都是什么类型,都有什么权限.

都有哪些方法,都叫什么名字,都是什么参数,都有什么权限.

java文件中涉及的信息都会在.class中有所体现.

区分一个变量在哪个内存区域中,最主要就是看变量的 " 形态 "(局部变量,成员变量,静态成员变量)

二、JVM的类加载机制

类加载,指的是java进程运行的时候,需要把.class 文件从硬盘,读取到内存,并进行一系列的校验解析的过程.

.class -> 类对象        硬盘 -> 内存

类的加载大体的过程可以分为5个步骤:

1. 加载

把硬盘上的.class文件,找到,打开文件,读取到文件的内容,

2. 验证

当前需要确保读到的文件的内容,是合法的. class文件(字节码文件)格式

3. 准备

给类对象,申请内存空间.

此时申请到的内存空间,里面的默认值,都是全0的.

4. 解析

主要是针对类中的字符串常量进行处理

硬盘中没有地址,引用类型的数据无法通过地址存储,就可以使用偏移量,等. class文件加载到内存中后,就有hello的地址了.

5. 初始化

针对类对象完成后续的初始化.

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

双亲委派模型(加载环节)

描述了如何查找. class文件的策略

JVM中进行类加载的操作,是有一个专门的模块,称为 " 类加载器 "

JVM中的类加载器默认是有三个的

BootstrapClassLoader   负责查找标准库目录

ExtensionClassLoader   负责查找扩展库目录

ApplicationClassLoader   负责查找当前项目的代码目录以及第三方库的目录

上述这三个类加载器,存在 "父子关系",类似于二叉树,有一个指针parent指向自己的父类加载器.

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

1.从ApplicationClassLoader 作为入口,开始工作.

2..ApplicationClassLoader 不会立即搜索自己负责的目录,会把搜索的任务交给自己的父亲.

3.代码就进入到ExtensionClassLoader 范畴了.

ExtensionClassLoader 也不会立即搜索自己负责的目录,也要把搜索的任务交给自己的父亲.

4.代码就进入到BootstrapClassLoader  范畴了.

BootstrapClassLoader  也不会立即搜索自己负责的目录,也要把搜索的任务交给自己的父亲.

5. BootstrapClassLoader 发现自己没有父亲,才会真正的开始搜索自己的目录,通过全限定类名,尝试在标准库目录中找到符合要求的.class文件

如果找到了,接下来直接进入打开文件/读文件等流程中.

如果没找到,回到孩子这一辈的类加载器中,继续尝试加载.

6. ExtensionClassLoader 收到父亲交回给他的任务后,搜索自己负责的目录

如果找到了,接下来直接进入打开文件/读文件等流程中.

如果没找到,回到孩子这一辈的类加载器中,继续尝试加载.

7. ApplicationClassLoader 收到父亲交回给他的任务后,搜索自己负责的目录.

如果找到了,接下来直接进入打开文件/读文件等流程中.

如果没找到,回到孩子这一辈的类加载器中,继续尝试加载.

由于ApplicationClassLoader没有孩子了,此时说明类加载过程失败了,就会抛出ClassNotFountException异常.

上述这一些列规则,只是JVM自带的类加载器,遵守的默认规则,如果自己写类加载器,也可以打破这种规则.

三、垃圾回收机制(GC)

引入了垃圾回收机制后,就不需要手动释放内存了.程序会判定内存是否还需要使用,不需要使用的就会被释放.

STW(stop the world)问题:触发垃圾回收机制的时候,很可能会使当前程序的其他的业务逻辑被暂停.

垃圾回收,是回收内存,JVM的内存有好几块,其中堆是GC的主要战场.

垃圾回收机制的具体展开:

1. 识别出垃圾.

判定一个对象之后是否还需要继续使用,如果一个对象没有任何引用,就会被视为垃圾.

如果有多个引用指向同一个对象,那些引用的生命周期又各不相同,此时情况就会比较复杂.

    1.1 引用计数

        给每个对象安排一个空间,记录有多少个引用指向当前对象,当垃圾回收机制发现这个计数为0,就可以回收这个空间了.

        但是引用计数会有一个问题,如果A对象的一个引用指向了B对象,B对象的一个引用又指向了A对象,然后指向AB的引用各自置为null,就会导致这两块空间都无法被回收 

2. 可达性分析(JVM所使用的)

本质上就是时间换取空间,再写代码的时候,会定义很多的变量,就可以从这些变量出发,尝试进行遍历.

所谓的遍历就是沿着这些变量中持有的引用类型的成员,在进行下一步的访问,无法被访问到的就会被视为垃圾.

2. 把标记为垃圾的对象内存空间进行释放
 

主要的释放方法有三种:

        a. 标记-清除

        把标记为垃圾的对象,直接释放掉.

        但是会导致内存碎片问题,所以一般不使用这个方案

        所谓内存碎片,就是一块完整的内存,其中有一些地方被标记为垃圾,被释放掉,但是时候申请内存的时候,如果总内存足够,但是因为有内存碎片,就会导致没有一块连续的内存的空间达到要申请的空间的大小,此时,去申请空间就会失败.

        例如,要申请1M的空间,总的空闲空间比1M 大,但是空闲空间是1000个碎片,每个碎片是10K,此时空闲空间是10M,但是每个碎片都是小于1M的,就会申请失败.

b. 复制算法

        复制算法,核心就是不直接释放内存,而是把不是垃圾的对象,复制到另一块内存.,然后把之间的空间全部释放.

        这样确实可以解决碎片问题,但是会导致:

        1. 总的可用空间变少了.

        2. 如果每次要复制的对象比较多,此时复制的开销就会很大.

        所以这种方法一般适用于少数对象存活.

c. 标记-整理

        类似于顺序表,释放一个空间后,会把后面的元素向前搬运.

        但是这种方法的搬运内存开销非常大.

分代回收

由于上述垃圾回收机制,都存在问题,所以JVM自己弄出了一个方案.

引入概念:对象的年龄

JVM中有专门的线程负责周期性扫描/释放

一个对象,如果被线程扫描了一次,可达了,年龄就+1(初始为0)

1. 当代码中new出一个新对象的时候,这个对象就是被创建在伊甸区的

2. 第一轮GC扫描完后,少数伊甸区中幸存的对象,就会通过复制算法,拷贝到生存区.

后续再进行扫面,如果这个对象再生存区中还存活者,就会继续被拷贝到另一半生存区中.

3. 如果这个对象在生存区中经过GC多轮扫描依旧存在,就会被拷贝到老年区代.

4. 老年代的对象,被GC扫描的频率就会大幅度降低了.

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

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

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

相关文章

折腾日记:如何在Mac上连接Esp32

个人博客地址 最近购买了一块Esp32单片机,在Mac环境上进行开发,并且成功点亮LED灯和连上屏幕,为什么会上手选择Esp32开发板,主要考虑它自带Wi-Fi和蓝牙,单价也不高,就算后面不玩了,也能转成物联…

深度学习:如何静悄悄地改变我们的日常生活

深度学习 深度学习:如何静悄悄地改变我们的日常生活一、消费电子产品智能手机与个人助理娱乐与社交媒体 二、医疗健康三、汽车与交通四、公共安全五、总结 深度学习:如何静悄悄地改变我们的日常生活 在近年来,深度学习技术因其强大的数据处理…

LibreOffice电子表格如何实现快速筛选并将结果放到新的工作表

如果是在excel或者wps中,可能大家都习惯了自动筛选,然后复制到新的工作表或者删除掉复制内容的办法。但是在LibreOffice中,经测试,大数据表的删除或者复制是非常慢的。这也是很多人放弃LibreOffice的原因之一。那么我们如何快速筛…

Flutter 使用ffigen生成ffmpeg的dart接口

Flutter视频渲染系列 第一章 Android使用Texture渲染视频 第二章 Windows使用Texture渲染视频 第三章 Linux使用Texture渲染视频 第四章 全平台FFICustomPainter渲染视频 第五章 Windows使用Native窗口渲染视频 第六章 桌面端使用texture_rgba_renderer渲染视频 第七章 使用ff…

【C语言】一节课拿捏---动态内存分配

谢谢观看!希望以下内容帮助到了你,对你起到作用的话,可以一键三连加关注!你们的支持是我更新地动力。 因作者水平有限,有错误还请指出,多多包涵,谢谢! 目录 一、 为什么要有动态内存…

PgSQL技术内幕 - psql与服务端连接与交互机制

PgSQL技术内幕 - 客户端psql与服务端连接与交互机制 简单来说,PgSQL的psql客户端向服务端发起连接请求,服务端接收到请求后,fork出一个子进程,之后由该子进程和客户端进行交互,处理客户端的SQL等,并将结果返…

【Python】一文向您详细介绍 __str__ 的作用和用法

【Python】一文向您详细介绍 str 的作用和用法 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通本硕&…

【CS.AI】AI引领编程新时代:深度探索GitHub Copilot

文章目录 引言0. TOP TAKEAWAYS 重要要点1. Copilot的基本功能2. 技术原理3. 优势与局限优势局限 4. 使用体验4.1 初次使用4.2 在 JetBrains 全家桶中使用 GitHub Copilot1. 安装插件2. 配置插件3. 使用 GitHub Copilot 4.3 日常开发4.4 体验与反馈 5. 对开发者生态系统的影响5…

梯度下降: 02. 批量梯度下降BGD,随机梯度下降SGD,小批量梯度下降MBGD

简介 本文从原理上介绍了三种梯度下降的方法,相同点,异同点,优缺点。 内容包含了数学公式的推导与说明 1. 梯度下降的3种方法 梯度下降分三类,原理基本相同,操作方式略有区别 批量梯度下降BGD(BatchGradient Descent):使用全量数据进行特征抽取,模型训练小批量梯度下降…

VueRouter3学习笔记

文章目录 1,入门案例2,一些细节高亮效果非当前路由会被销毁 3,嵌套路由4, 传递查询参数5,命名路由6,传递路径参数7,路径参数转props8,查询参数转props9,replace模式10&am…

【C++】深入理解decltype和decltype(auto)

深入理解decltype和decltype(auto) 一、decltype语法介绍二、decltype的推导规则1. expr不加括号2. expr加上括号 三、关于decltype的CV属性推导四、 decltype(auto) 的使用 一、decltype语法介绍 decltype关键字是C11新标准引入的关键字,它…

Hadoop3:MapReduce源码解读之Map阶段的Job任务提交流程(1)

3、Job工作机制源码解读 用之前wordcount案例进行源码阅读,debug断点打在Job任务提交时 提交任务前,建立客户单连接 如下图,可以看出,只有两个客户端提供者,一个是YarnClient,一个是LocalClient。 显然&a…

Objective-C 学习笔记 | 基础

Objective-C 学习笔记 | 基础 参考书:《Objective-C 编程(第2版)》 第1部分 入门 Objective-C语言是以C语言为基础的,但增加了对面向对象编程的支持。Objective-C语言是用来开发在苹果iOS以及OS X操作系统上运行的应用的编程语…

植物大战僵尸杂交版 2.0 下载及配置图文教程

文章目录 Part.I IntroductionPart.II 下载Chap.I 下载地址Chap.II 网盘直链下载 Part.III 配置Chap.I 解压与安装Chap.II 加载存档Chap.III 其他设置 Reference Part.I Introduction 最近看大仙儿直播植物大战僵尸,觉得挺好玩的。它大概长这样: 就上网…

使用proteus仿真51单片机的流水灯实现

proteus介绍: proteus是一个十分便捷的用于电路仿真的软件,可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域,使用代码实现电路功能的仿真。 汇编语言介绍: 百度百科介绍如下: 汇编语言是培养…

Python GUI编程:深入探索现代GUI库及其创新应用

目录 引言 Python GUI库概览 1. Tkinter 2. PyQt/PySide 3. wxPython 4. Kivy 5. PyGTK 6.FLTK (pyFLTK) 创新应用案例 1. 交互式数据分析工具 2. 智能物联网(IoT)仪表板 3. 增强现实(AR)辅助设计软件 4. 跨平台的科学计算软件 5. 交互式教育软件 实战示例1&…

.NET MAUI 了解MVVM

MVVM 模式中有三个核心组件:模型、视图和视图模型。 每个组件的用途不同。 下图显示了这三个组件之间的关系。 视图 视图负责定义用户在屏幕上看到的结构、布局和外观。 理想情况下,每个视图在 XAML 中定义,代码隐藏有限,不包含业…

linux shell实现打印国际象棋棋盘

chess.sh #!/bin/bashfor i in {1..8} dofor j in {1..8}dosum$[ij]if [ $[sum%2] -eq 0 ];thenecho -ne "\033[46m \033[0m"elseecho -ne "\033[47m \033[0m"fidoneecho done验证:

微信小程序学习笔记(4)

文章目录 1、< template >< / template >2、样式导入i、wxmlii、wxss 3、flex布局i、容器属性ii、项目属性 1、< template >< / template > 模板可以重复调用 首先要定义一个模板&#xff1a; <template name"test"><view>{{…

AbstractMap和SimpleEntry

一、AbstractMap 位置&#xff1a;在java.util包 二、SimpleEntry 1、概述 继承了Map中的内部接口Entry<K,V> SimpleEntry<K,V>不仅继承了Map.Entry<K,V>&#xff0c;还继承了序列化的接口 2、构造方法 方法说明SimpleEntry(K key,V value)通过键值对初…