【笔记】深入理解JVM机制

  • 🎥 个人主页:Dikz12
  • 📕格言:吾愚多不敏,而愿加学
  • 欢迎大家👍点赞✍评论⭐收藏

目录

 JVM 运⾏流程图

 JVM 中内存区域划分

 方法区 / 元数据区

 栈

 程序计数器

 本地方法栈

内存区域总结 

 JVM 中类加载过程

双亲委派模型

JVM 中的垃圾回收机制

找到垃圾 

 引用计数 (Python,PHP)

 可达性分析(Java) 

回收垃圾

标记清除

 复制算法

标记整理

堆的新生代 和 老生代


 JVM 运⾏流程图

 JVM 中内存区域划分

一个运行起来的Java进程,就是一个JVM虚拟机,就需要从操作系统申请一块内存,然后把这个内存,划分成不同区域,每个区域都有不同的作用.

比如:学校这么大场地,就相当于申请了一大块内存空间.

 方法区 / 元数据区

jdk1.7及其以前叫做 方法区;从jdk1.8开始叫做元数据区.

元数据区存储内容:用来存储被虚拟机加载的类信息、常量、静态变量. (这里存储的是类对象, .class文件,加载到内存之后,就成了类对象)

堆存储的内容:程序创建的所有对象都保存在堆里.(就是代码new的对象)

堆⾥⾯分为两个区域:新⽣代和⽼⽣代.


 

具体在垃圾回收机制里说明!!!

 栈

 栈存储的内容:代码执行过程中,方法之间的调用关系.(a->b->c)

每个栈帧里就包含了方法的入口, 方法的返回的位置,方法的形参,方法的返回值,局部变量......等

 程序计数器

 程序计数器是一块比较小的空间,主要就是存放一个“地址”,下一条要执行的指令,在内存中的哪个地方.

 刚开始调用方法,程序计数器,记录的就是方法入口的地址;随着一条一条的执行指令,每执行一条,程序计数器的值就会自动更新,去指向下一条指令.

class Test{public void a(){...}public void b(){...}
}

这里的方法a 和 方法b都会被编译成二进制的指令,就会被放到.class文件中.

 本地方法栈

本地方法栈,指的是使用nativa关键字修饰的方法;这个方法不是使用Java实现的,而是在JVM内部通过C++代码实现的. (JVM内部的C++代码调关系) 

内存区域总结 

 

 JVM,是一个运行Java进程,一个进程可以包含多个线程,内存区域有如何划分?

虚拟机栈及程序计数器,都是每个线程都有一份.

堆和元数据区在jvm进程中只有一份,线程共享.

JVM 有10个线程,就会有10个虚拟机栈,也会有10个程序计数器.

 JVM 中类加载过程

对于一个类来说,它的生命周期如下:

 课本上 和 官方文档 把这个类加载的过程,主要是分成了五个部分.

1.加载.   找到.class文件,打开文件,读取文件内容. 代码中,会给定某个类的“全限定类名”,jvm就会根据这个类名,在一些指定的目录范围内查找.     (全限定类名:java.lang.Sring 、java.util.ArrayList)

2.验证.   检验 .class 文件是一个二进制的格式.(某个字节,都是有特定的含义)     

                           

java8规范要求:Chapter 4. The class File Format

 3. 准备.    给类对象分配内存空间,这里只是分配内存空间,还没有初始化呢,此时这个空间上的内存数值,全是0.

4.解析.     针对类对象中包含的字符串常量进行处理,进行一些初始化操作. java代码中用到的 字符串常量,在编译之后也会进入到.class文件中.

比如: final String str = "test".

在.class文件的二进制指令中,也会有一个 str 这样的引用被创建出来;由于应用本质上保存的是一个变量的地址,在 .class文件是一个文件,不涉及到内存地址,就会先设置成一个“文件的偏移量”通过偏移量,就能找到“test”这个字符串所在的位置.(真正被加载到内存的时候,再把这个偏移量替换成真正的内存地址)

5. 初始化.   针对类对象进行初始化,就是把类对象中需要的各个属性都设置好.

双亲委派模型

1.BootStrap :启动类加载器.
2. Ext ClassLoader :扩展类加载器。加载 lib/ext ⽬录下的类.
3. App ClassLoader:应⽤程序类加载器.
4. ⾃定义加载器:根据⾃⼰的需求定制类加载器.

 JVM中,内置了,三个类加载器:

过程: 

1. ⼀个类加载器收到了类加载的请求,它⾸先不会⾃⼰去尝试加载这个类.

2. ⽽是把这个请求委派给⽗类加载器去完成,每⼀个层次的类加载器都是如此.
3. 所有的加载请求最终都应该传送到最顶层的启动类加载器中
4. 只有当⽗加载器反馈⾃⼰⽆ 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,⼦加载器才会尝试⾃⼰去完成加载.

5.当子类加载器AppClassLoader,也没找到就会抛出一个ClassNotFoundException.

JVM 中的垃圾回收机制

 GC垃圾 回收的目标,其实就是 内存中的对象. 对于Java来说就是 new出来的对象.

栈里放的是局部变量,是跟随栈帧的生命周期走的.(方法执行结束,栈帧销毁,内存自然释放)

静态变量,生命周期就是整个程序,始终在,就意味着,静态变量时无需释放的.

GC可以理解两大步骤:  1. 找到垃圾.        2.释放垃圾  

找到垃圾 

 引用计数 (Python,PHP)

为什么Java不使用引用计数???

1.比较浪费内存.

计数器,也要有两个字节.如果对象本身就很小,这个计数器占据的空间比例就很大了.

比如对象本身就两个字节,计数器占据的空间就是50%. (如果对象小并且多,计数器占据的空间就难以忽视了)

2.引用计数机制,存在“循环引用”问题.

 可达性分析(Java) 

 有一个 或者 一组线程,周期性的扫描我们代码中的所有对象. 

从一些特定的对象出发,尽可能的进行访问的遍历,把所有都能够访问到的队象,都标记成"可达"

反之,经过扫描之后,未被标记的对象,就是“垃圾”了.

可达性分析,是周期性进行的,所以是比较消耗系统资源,开销比较大.是时间换空间的手段 

回收垃圾

标记清除

简单粗暴的方式,比如,申请了一块内存空间,上面有一些对象,通过可达性分析发现 2 和 4是垃圾, 就直接把对应的对象的内存,直接释放掉,就是标记清除方案.

 这个方案其实非常不好,会产生很多的内存碎片;释放内存,目的是为了让别的代码能够申请. 申请内促,都是申请到“连续”的内存空间 ; 随着时间的推移,内存碎片的情况,就会越来越严重,最会导致后续内存申请举步维艰.

 复制算法

 通过复制的方式,把有效的对象,归类到一起,在统一释放剩下的空间.

比如,一块内存空间先一分为二,一次只用一其中一半, 里面有一些对象,假设1,3,5垃圾,通过复制算法,把2 和 4 复制到另外一边,就可以把左侧的整体释放掉.

 

 这个方案可以有效的解决内存碎片问题,缺点也是很明显的;

 1.内存要浪费一半,利用率不高.      

 2.如果有效对象非常多,复制的开销就很大了.

标记整理

 既能够解决内存碎片的问题,又能处理复制算法中的利用率.

过程就类似于顺序表删除元素的搬运操作. 

比如,一块内存空间,通过可达性分析,1,3,5是垃圾, 把2搬运到1的位置.... 

 

 

搬运开销仍然很大!!

实际上,JVM 采取的释放思路,是上述基础思路结合体.(让不同的方案,扬长避短) 

堆的新生代 和 老生代

垃圾回收只是针对堆进行的, 堆的内存空间会分成两部分,不是等分的,具体怎么分不一定,左边称为“新生代”,右边称为“老年代”.

新生代:又进一步的划分,分为 幸存区 和 伊甸区.

幸存区:等分的两部分,每次只用一块. 正好就是复制算法的体现.

伊甸区:放的是刚 new出来的对象.(还没有经过可达性扫描)

 

 经验规律: 从对象诞生,到第一轮可达性分析扫描,这个过程中虽然时间不长,基本就是 毫秒 - 秒(这个时间维度,对于程序的眼中也挺长了),在这个时间里大部分的对象都会成为垃圾.

 1.伊甸区 -> 幸存区 (复制算法)

       每一轮GC扫描之后,都会把有效的对象,复制到幸存区中,伊甸区就可以整个释放了. 由于经验规律,真正需要复制的对象不多,非常适合复制算法.

2. GC 扫描线程也会扫描 幸存区. 就会把活过GC扫描的可达对象,复制到幸存区的另一部分. 幸存之前的复制,每一轮会复制多个对象,每一轮也可以淘汰掉一些对象.

3. 当这个对象已经在幸存区存活很多轮GC扫描之后,JVM 就认为这个对象,短时间内是应该释放不掉,就会把这个对象复制到老年代.

 4. 进入老年代的对象,虽然也会被GC 扫描,扫描频率就会比新生代,低很多.

   (也是为了减少GC扫描的开销,要挂早就挂了!!!)

   

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

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

相关文章

Go第三方框架--gin框架(一)

序言 Gin框架作为go语言使用最多的web框架,以其快速的响应速度和对复杂http路由配置的支持受到程序员和媛们的喜爱,几乎统治了web市场。但作为一名合格的程序员,要知其然更要知其所以然,不然八股文背的也没有啥意思。本着这个原则…

【Java程序设计】【C00368】基于(JavaWeb)Springboot的箱包存储系统(有论文)

TOC 博主介绍:java高级开发,从事互联网行业六年,已经做了六年的毕业设计程序开发,开发过上千套毕业设计程序,博客中有上百套程序可供参考,欢迎共同交流学习。 项目简介 项目获取 🍅文末点击卡片…

【MySQL数据库】数据类型和简单的增删改查

目录 数据库 MySQL的常用数据类型 1.数值类型: 2.字符串类型 3.日期类型 MySQL简单的增删改查 1.插入数据: 2.查询数据: 3.修改语句: 4.删除语句: 数据库 平时我们使用的操作系统都把数据存储在文件中&#…

3.3 数据定义 数据库与系统概论

目录 3.3.1 模式的定义与删除 1. 定义模式 2. 删除模式 CASCADE(级联) RESTRICT(限制) 3.3.2 基本表的定义、删除与修改 表的定义 2.数据类型 3. 模式与表 4. 修改基本表 5. 删除基本表 3.3.3 索引的建立与删除 1. …

如何备考2024年AMC10:吃透2000-2023年1250道真题(限时免费送)

我们今天继续来随机看5道AMC10真题,以及详细解析,这些题目来自1250道完整的官方历年AMC10真题库。通过系统研究和吃透AMC10的历年真题,参加AMC10的竞赛就能拿到好名次。即使不参加AMC10竞赛,掌握了这些知识和解题思路后初中和高中…

2015年认证杯SPSSPRO杯数学建模C题(第一阶段)荒漠区动植物关系的研究全过程文档及程序

2015年认证杯SPSSPRO杯数学建模 C题 荒漠区动植物关系的研究 原题再现: 环境与发展是当今世界所普遍关注的重大问题, 随着全球与区域经济的迅猛发展, 人类也正以前所未有的规模和强度影响着环境、改变着环境, 使全球的生命支持系统受到了严重创伤, 出现了全球变暖…

Flutter 旋转动画 线性变化的旋转动画

直接上代码 图片自己添加一张就好了 import dart:math;import package:flutter/material.dart;import package:flutter/animation.dart;void main() > runApp(MyApp()); //旋转动画 class MyApp extends StatelessWidget {overrideWidget build(BuildContext context) {re…

RMAN 备份恢复、删除归档

RMAN冷备全库 rman target / list backup shutdown immediate startup mount #不要自动备份control file set nocfau; #注意要先备份数据库,然后备份控制文件,因为数据库的备份位置记录在控制文件中。 #备份数据库 backup database format /mnt/disk01/r…

vue 中实现下载后端返回的流式数据

验证是否是blob /*** Event 验证是否为blob格式* */export async function blobValidate(data) {try {const text await data.text();JSON.parse(text);return false;} catch (error) {return true;}}get请求 /*** Event: get请求下载后端返回的数据流* description: url[Stri…

Redis-指定配置启动

基础篇Redis 3.3.5.指定配置启动 如果要让Redis以后台方式启动,则必须修改Redis配置文件,就在我们之前解压的redis安装包下(/usr/local/src/redis-6.2.6),名字叫redis.conf: 我们先将这个配置文件备份一份…

利用 Scapy 库编写 ARP 缓存中毒攻击脚本

一、ARP 协议基础 参考下篇文章学习 二、ARP 缓存中毒原理 ARP(Address Resolution Protocol)缓存中毒是一种网络攻击,它利用了ARP协议中的漏洞,通过欺骗或篡改网络中的ARP缓存来实施攻击。ARP协议是用于将IP地址映射到物理MAC…

警务数据仓库的实现

目录 一、SQL Server 2008 R2(一)SQL Server 的服务功能(二)SQL Server Management Studio(三)Microsoft Visual Studio 二、创建集成服务项目三、配置“旅馆_ETL”数据流任务四、配置“人员_ETL”数据流任…

OM6626低功耗M4内核低睡眠电流BLE5.3 SoC国产ESL蓝牙方案芯片

目录 OM6626简介OM6626主要特性射频特性PUM特性安全性SDK代码微信号:dnsj5343OM6626最小系统Demo板 OM6626简介 OM6626是功能强大、性能稳定、超低功耗的蓝牙SoC芯片,适用于各种低功耗蓝牙和专有的2.4GHz应用场景。OM6626还集成了电源管理单元 (PMU)&am…

机器视觉检测设备的组成要素

机器视觉检测设备是一种先进的自动化检测技术工具,它利用光学、图像处理和计算机硬件及软件技术模拟并扩展人类的视觉功能,以实现对产品或目标物体进行自动化的尺寸测量、缺陷检测、表面质量评估、颜色识别、形状匹配以及位置判断等功能。这种设备通常包…

PyCharm环境下Git与Gitee联动:本地与远程仓库操作实战及常见问题解决方案

写在前面:本博客仅作记录学习之用,部分图片来自网络,如需引用请注明出处,同时如有侵犯您的权益,请联系删除! 文章目录 前言下载及安装GitGit的使用设置用户签名设置用户安全目录Git基本操作Git实操操作 Pyc…

Python高阶函数库之functools使用详解

概要 functools是Python标准库中的一个模块,它提供了一系列用于高阶函数:即那些作用于或返回其他函数的函数。这些工具主要用于函数式编程风格,其中包括用于创建函数包装器的装饰器。 functools简介 functools库的目的是为了高阶函数,特别是那些涉及到函数转换的操作提供…

数据仓库的魅力及其在企业中的应用实践

数据仓库,这一创新性的概念来自于比尔恩门,从1980年代末提出以来,便凭借其独特的架构设计和强大的数据处理能力,在全球商业领域中掀起了一场革命。它不仅是解决企业海量数据存储和查询需求的关键技术,更是推动企业实现…

【Java】哈希表

文章目录 一、概念二、哈希冲突2.1概念2.2设计合理的哈希函数-避免冲突2.3调节负载因子-避免冲突2.4闭散列-冲突解决(了解)2.5开散列/哈希桶-冲突解决(重点掌握) 三、代码实现3.1成员变量及方法的设定3.2插入3.3重新哈希3.4 获取到…

免费客服系统大揭秘!有什么好用的免费客服系统推荐?

贵的不一定是好的,合不合适才最重要!有什么好用的免费客服系统吗?现下服务经济的发展的风潮已经席卷到了各行各业。 企业不仅要提供好的产品,还需要好的服务。客服系统作为企业与客户重要的沟通渠道,越来越多的企业正在…

记录些LLM相关的知识

SOTA SOTA是"State-of-the-Art"的缩写,指的是某个技术或领域中目前最先进的技术或方法。在语音合成领域,SOTA语音合成效果指的是使用最新的研究和技术所达到的最佳语音合成效果。这通常包括高清晰度的语音输出,自然的语音流畅度&a…