Java虚拟机 - JVM

news2024/9/29 11:26:40

JVM的内存区域划分

JVM它其实也是一个进程,进程运行的过程中,会从操作系统中申请一些资源.内存就是其中的一种.这些内存就支撑了java程序的运行.JVM从系统中申请的一大块内存,会根据实际情况和使用用途来划分出不同的空间,这个就是区域划分.它一般分为 堆区, 栈区, 程序计数器, 元数据区4个区域.

堆区

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

栈区

栈区分为本地方法栈和虚拟机栈. 本地方法栈是jvm通过c++写的代码的调用关系和局部变量.一般我们只关心虚拟机栈. 虚拟机栈是记录了java代码的调用关系和java代码的局部变量.

程序计数器

这是一块小区域,专门用来存储下一条要执行的java指令的地址,和x86cpu中的eip寄存器差不多.

元数据区

在之前也叫做 "方法区". 它里面记录的是类的信息,方法的信息, 一个程序有哪些类,每个类有哪些方法,方法里面都会包含哪些指令,都会记录在元数据区中.想我们的代码中的各种逻辑都会转化为java字节码,这些字节码就会在程序运行的时候被jvm加载到内存中,放到方法区当中.程序怎么执行就会按照元数据区中的java字节码来依次执行.

注意: 这里堆和元数据区只有一份,但是栈区和程序计数器由N份,和线程数目相关.

JVM的类加载机制

这里的类加载就是java进程来运行的时候,需要把.class文件从硬盘读取到内存,且进行一系列的校验解析的过程. 这里加载的过程可以分为5个步骤. 加载 - 验证 - 准备 - 解析 - 初始化.

加载

大概就是把硬盘中的.class文件找到,打开文件且读取到文件内容.

验证

把当前读到的文件内容需要确保是合法的.class文件格式.

准备

给类对象申请内存空间.这里的申请到的内存空间,里面的默认值都是0.类对象中的静态成员变量的值也就是0)

解析

这里就是对类中的字符串常量进行处理.将常量池中的符号引用转换为直接引用的过程.(符号引用可以理解为字符串和它的引用在文件中有偏移量,直接引用则就是地址).

初始化

针对类对象完成后续的初始化过程(这里还会执行静态代码块的逻辑,父类的加载)

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

这里描述了怎么样来查找.class文件的策略.在我们的JVM中进行类加载的操作,会有一个专门的模块 - "类加载器(ClassLoader)". JVM中有三个ClassLoader.这里类加载器的作用就是给它一个带有包名的类名,来找到对应的.class文件.

三个库的作用:

BootstrapClassLoader: 负责查找标准库中的目录.

ExtensionClassLoader: 负责查找扩展库中的目录.

ApplicationClassLoader: 负责查找当前项目的代码目录和第三方库.      

这三个加载器的关系类似于父子关系.

工作过程

1. 先以ApplicationClassLoader为入口,开始工作.,但是它不会立刻开始查找自己负责的目录,而是将任务交给它的父亲.

2. 任务到ExtensionClassLoader,它也不会立刻开展工作,而是交给它的父亲.

3. 任务到BootsstrapClassLoader,它才会开始真正的搜索负责的目录.通过全限定类名,来尝试在标准库中找到符合的.class文件.找到了就进入打开文件,读文件的流程.没找到则交给它的孩子来处理.

4. ExtensionClassLoader拿到父亲给它的任务后,也会通过全限定类名,在扩展库中查找符合的.class文件.找到了就进入读文件的流程.没找到再交给它的孩子处理.

5. ApplicationClassLoader拿到夫妻给它的任务后,也会通过全限定类名,在项目中的目录和第三方库的目录中查找.找到了就进入读文件流程.没找到说明加载失败.则会抛出ClassNotFoundException异常.

这样设定的目的其实最主要的就是确保这几个类加载器的优先级. 按照这样的方式就算你自己写的类不小心和标准库中的类名字重复了,也可以避免导致标准库中的类失效.

JVM的垃圾回收机制(GC)

JVM的垃圾回收,说的就是将内存回收.在JVM的多个区中. 程序计数器不需要GC,栈不需要,因为它的局部变量在代码块执行结束后就会进行自动销毁. 元数据区也不需要,它一般都是涉及到类加载,很少涉及到类卸载. 这里最主要使用GC的就是堆区.因为它里面记录的是对象,而代码中可能会new出许许多多的对象,有的对象可能不使用了,就需要销毁.所以这里的内存回收,也可以看成是对象回收.

垃圾回收分为两步:

1. 识别出垃圾,哪些对象是垃圾,哪些对象不是垃圾.

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

识别垃圾

这里识别一个对象是不是需要继续使用,就是判断还有没有引用在指向它.如果没有,它就可以视为垃圾.这里有两种方法: 1. 引用计数 2. 可达性分析

引用计数

这个方法在JVM中并没有使用,但是在其他的主流语言中还是在广泛应用中.

它的处理方式就是:

给每一个对象安排一个额外的空间,这个空间里就保存当前有几个引用. 而另一边会有专门的扫描线程,去获取到当前每个对象的引用计数的情况,一但发现这个对象的引用计数为0,就代表可以释放了.

但是它会存在一些问题:

1. 会消耗额外的内存空间.尤其是当对象比较小时,你的计数器消耗的空间可能就达到对象的一半了.

2.引用计数可能会产生循环引用的问题.

可达性分析(JVM使用的方法)

它的本质就是用时间来换空间. 它就不会产生额外的空间和循环引用的问题.

在代码中,会定义出很多变量,栈上的局部变量,堆上的成员变量,方法区的静态变量,常量池中引用的对象... 它就可以从这些变量作为起点,去进行遍历.这个遍历就是沿着这些变量持有的引用类型的成员,再进行下一步的访问. 可以遍历到的对象就不是垃圾,反之.

这里的遍历我们可以想象为二叉树的遍历.一但有一个节点为null,那这个结点后面的也都为null,也就是垃圾.

JVM中会存在扫描线程,对代码不断进行遍历.

清理垃圾

清理垃圾就是将被标记的内存空间进行释放.这里释放有三种方法.

标记 - 清除

这里就是直接将标记为垃圾的对象直接释放掉.但是一般不会使用这个方案.因为它会有内存碎片问题.直接释放,就会产生很多小的,离散的空闲内存空间,这就可能导致后续的内存申请失败.因为内存申请一般都是申请一块连续,大范围的空间.

复制

它的核心就不是直接释放内存,也是将不是垃圾的对象,复制到另一半的空间中(它会将可用内存空间分为两半). 

这样子就规避了内存碎片化的问题,但是也会有一些缺点.

1. 总用的内存空间变少了.

2. 如果每次需要复制的对象比较多,复制开销就会很大了(它适合大部分对象都释放,少部分对象存活,这个时候使用复制)

标记 - 整理

这个方式就类似于顺序表中的删除中间元素,需要进行搬运.通过这个过程,也就解决了内存碎片的问题,但是它这里的搬运内存开销会很大.

JVM的分代回收

 因为上面方法的优缺点,JVM就结合上面的思想,搞出来了一个综合方案.

JVM会给对象进行年龄记录,被JVM的扫描线程扫描过一次后就加一岁,起始岁数为0. 而还给堆内存划分了两个区域:分为为新生代和老年代.且新生代中还分了三个区:伊甸区和两个生存区.

 处理流程:

1. 当代码中new出一个新的对象时,就是创建在伊甸区中的,伊甸区中会有很多对象.(放在里面是有一个经验规矩: 伊甸区的对象大多都是活不过第一轮GC的,"朝生夕死")

2. 当第一轮GC后,少部分存活下来的对象,就会通过复制算法拷贝到生存区中(GC后存活下来的对象不会很多,复制开销也不会很大).后续还会有GC扫描,不仅会扫描伊甸区,还会扫描生存区.生存区的大多数对象也会在扫描中被标记为垃圾.少部分存活的,又会继续复制算法拷贝到另一个生存区汇中.这样不断往复,且每过一次GC,生存下来的对象年龄就会+1.

3. 当一个对象在生存区中经历了若干次GC还没有消亡,则JVM就会认为它的生命周期特别长,就会将它从生存区拷贝到老年代.

4. 老年代的对象也会被GC扫描,但是扫描频率会大大降低.

5.当老年代的对象消亡时,JVM就会按照标记整理的方式,释放内存(老年代的对象很少,所以搬运开销不会很大)


到这里,上面的就是JVM中GC的核心思想.但是在一些实现细节上还是会有一些变数和优化~

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

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

相关文章

LeetCode周赛——388

1.重新分装苹果&#xff08;贪心&#xff09; 思路 箱子大小降序排序&#xff0c;按顺序装 class Solution { public:int minimumBoxes(vector<int>& apple, vector<int>& capacity) {int n apple.size(), m capacity.size();int sum 0;for(int i 0;…

python_Anaconda虚拟环境导出以及重现

文章目录 1. 场景2. 解决方案2.1 方案一&#xff1a;直接将打包&#xff0c;然后将包传输到另外一台服务器2.2 方案二&#xff1a;导出环境所有的包名及版本&#xff0c;然后重新安装 1. 场景 我们有时候需要把一个虚拟环境迁移到别的服务器上面去&#xff0c;这时候&#xff…

多项式回归算法模拟

python3.6 环境 import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression from sklearn.preprocessing import PolynomialFeatures# 生成随机数作为x变量&#xff0c;范围在-5到5之间&#xff0c;共100个样本 x np.random.un…

基于boost库的搜索引擎项目

文章目录 一、项目背景二、什么样的搜索引擎三、搜索引擎的宏观图原理四、Parse模块4.1下载boost库源代码4.2提取boost库中以.html为结尾的文件4.2.1 boost库的简单使用 4.3数据清洗(去标签化)4.3.1数据清洗的具体实现 4.4将清洗后的数据写入到raw.txt文件中 五、正排索引 vs 倒…

【数据结构七】堆与PriorityQueue详解

堆 在Java中有一种数据结构基于队列&#xff0c;并保证操作的数据带有优先级&#xff0c;该数据结构应该提供了两个最基本的操作&#xff0c;一个是返回最高优先级对象&#xff0c;一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。它的底层使用了堆这种数据结…

day-19 合并后数组中的最大元素

思路&#xff1a;从后向前遍历数组&#xff0c;用tans记录每一种可能的最大值&#xff0c;ans为实际最大值。 注意&#xff1a;若ans0,返回nums[0] 要用long code class Solution {public long maxArrayValue(int[] nums) {long ans0;long tans0;boolean flagtrue;for(int in…

SpringBoot接口添加IP白名单限制

实现流程&#xff1a; 自定义拦截器——注入拦截器——获取请求IP——对比IP是否一致——请求返回 文章背景&#xff1a; 接口添加IP白名单限制&#xff0c;只有规定的IP可以访问项目。 实现思路&#xff1a; 添加拦截器&#xff0c;拦截项目所有的请求&#xff0c;获取请求的…

MySQL 篇-深入了解事务四大特性及原理

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 事务的概述 2.0 事务的特性 2.1 原子性 2.2 一致性 2.3 持久性 2.4 隔离性 2.4.1 脏读问题 2.4.2 不可重复读问题 2.4.3 幻读问题 3.0 事务的四个隔离级别 3.1…

#QT(一种朴素的计算器实现方法)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;这是全靠自己想法写的计算器&#xff0c;没有参考任何教程。 &#xff08;1&#xff09;这个计算器只要有运算符敲入就会进行一次运算&#xff0c;所以他没有先后之后&#xff0c;无法满足运算优先级。 &#xff08;2&#xff…

服务器集群 -- nginx配置tcp负载均衡

当面临高流量、高可用性、水平扩展、会话保持或跨地域流量分发等需求时&#xff0c;单台服务器受限于硬件资源、性能有限不能满足应用场景的并发需求量时&#xff0c;引入负载均衡器部署多个服务器共同处理客户端的并发请求&#xff0c;可以帮助优化系统架构&#xff0c;提高系…

【CSP试题回顾】201712-2-游戏

CSP-201712-2-游戏 解题思路 代码实现了一个模拟游戏过程的算法&#xff0c;其中n个小朋友围成一圈&#xff0c;按照顺时针方向依次编号从1到n&#xff0c;然后按顺时针方向依次报数。每当报的数是k的倍数或者个位数是k时&#xff0c;报数的小朋友会被淘汰。游戏继续进行&…

关于使用elementUI中select和el-checkbox-group的回显问题

网上看到很关于这个的问题回显&#xff0c;各式各样&#xff0c;没有绝句自己的问题&#xff0c;总重问题出在数据格式上 select和el-checkbox-group el-checkbox 都是字符串数组格式&#xff1a;[12,13,....]; 我写的格式是id是选中的id组成的回显数据格式&#xff1b; 如…

【爬虫】requests.post请求中的data和json使用区别

请求体是键值对形式&#xff08;无花括号&#xff09;&#xff0c;请求时需要使用data参数处理。 代码&#xff1a; data {...} ret requests.post(url, headersheaders, datadata)请求体是字典形式&#xff08;有花括号&#xff09;&#xff0c;请求时需要使用json参数处理。…

第16届大广赛XPPen都有哪些参赛命题

截至到发文时间&#xff0c;2024年3月14日&#xff0c;第16届大广赛已经累计公布了6个品牌命题&#xff0c;本文就给大家介绍一下XPPen命题的详细细节。 XPPen为汉王友基旗下全球知名数字艺术创新品牌&#xff0c;专注消费级用户创作需求&#xff0c;品牌产品覆盖全球160多个国…

C/C++中strcpy,strcat,strstr以及strncpy,strncat,strncmp的使用

1、首先我们来介绍strcpy的使用从这个函数的名字来看它应该是属于字符串的拷贝&#xff0c;string copy。 那么这个函数是怎么用的呢&#xff1f;下面我么来介绍她的基本结构。 char * strcpy ( char * destination, const char * source );由上述可知它需要两部分 一个是目标字…

如何在CentOS7搭建DashDot服务器仪表盘并实现远程监控

文章目录 1. 本地环境检查1.1 安装docker1.2 下载Dashdot镜像 2. 部署DashDot应用3. 本地访问DashDot服务4. 安装cpolar内网穿透5. 固定DashDot公网地址 本篇文章我们将使用Docker在本地部署DashDot服务器仪表盘&#xff0c;并且结合cpolar内网穿透工具可以实现公网实时监测服务…

【Python】新手入门学习:详细介绍里氏替换原则(LSP)及其作用、代码示例

【Python】新手入门学习&#xff1a;详细介绍里氏替换原则&#xff08;LSP&#xff09;及其作用、代码示例 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyT…

ArcGIS学习(十五)用地适宜性评价

ArcGIS学习(十五)用地适宜性评价 本任务给大家带来的内容是用地适宜性评价。 用地适宜性评价是大家在平时工作中最常接触到的分析场景之一。尤其是在国土空间规划的大背景下,用地适宜性评价变得越来越重要。 此外,我们之前的任务主要是使用矢量数据进行分析。本案例是主讲…

vs2022 错误(活动) E1696 无法打开 源 文件 “bits/stdc++.h“解决办法

一、创建stdc.h的头文件 随便找一个项目->添加->新建项->头文件->命名为stdc.h->添加 二、复制下述代码->保存 ​ // C includes used for precompiling -*- C -*-// Copyright (C) 2003-2017 Free Software Foundation, Inc. // // This file is part of …

镭雕机:如何利用激光技术实现高质量的产品标记

镭雕机是一种利用激光技术实现高质量产品标记的设备。它通过激光束在各种不同的物质表面进行精确的打标&#xff0c;可以产生永久性的标记效果&#xff0c;这些标记不仅精美&#xff0c;而且具有高度的精度和清晰度。以下是镭雕机如何利用激光技术实现高质量产品标记的详细过程…