【笔记】深入理解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.mzph.cn/news/771242.shtml

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

相关文章

C++ STL- list 的使用以及练习

目录 0.引言 1. list 介绍 2. list 使用 2.1 构造函数 2.2 list iterator 的使用 3 list capacity 4. list element access 5. list modifiers 6. list 迭代器失效 7. list 与vector 对vector 8. OJ 题讲解 删除链表的倒数第 N 个节点: 0.引言 …

Jetson AGX ORIN 配置 FGVC-PIM 神经网络(包含 arm64 下面 torch 和 torchvision 配置内容)

Jetson AGX ORIN 配置 FGVC-PIM 神经网络 文章目录 Jetson AGX ORIN 配置 FGVC-PIM 神经网络配置 ORIN 环境创建 FGVC-PIM 虚拟环境安装 PyTorch安装 torchvision安装其他依赖包 配置 ORIN 环境 首先先配置 ORIN 的环境,可以参考这个链接: Jetson AGX …

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

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

JavaScript中的Lexical Environment

概要 本文主要介绍JavaScript中的一个重要概念Lexical Environment,它可以帮助我们解释我们为什么可以通过嵌套方法,共享数据,以及为什么可以在函数中定义一个和全局变量同名的变量,并且不会影响到全局变量。 基本分析 基本概念…

如何使用Python进行网络安全与密码学【第149篇—密码学】

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 用Python进行网络安全与密码学:技术实践指南 随着互联网的普及,网络…

几个常用的AI工具

人工智能大模型的出现对人类社会产生了深远的影响,这些影响既包括积极的方面,也包括一些潜在的挑战: 1. **提高效率**:AI大模型能够快速处理大量数据,提高工作效率,尤其在数据分析、自然语言处理等领域。 2. **辅助决…

面向对象【枚举类】

文章目录 枚举类定义枚举类enum 方式定义的要求和特点 enum 中常用方法实现接口的枚举类 枚举类 枚举类是一种特殊的类,它用于定义一组固定数量的常量。枚举类在实际开发中非常有用,因为它们可以增加代码的可读性和可维护性。本文将介绍Java枚举类的定义…

Java基于微信小程序的校园请假系统

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#…

【Java程序设计】【C00370】基于(JavaWeb)Springboot的公司进存销管理系统(有论文)

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

视频记录历史播放位置效果

简介 每次打开页面视频从上一次的播放位置开始播放 利用lodash库做节流 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…

UI界面设计是什么?一篇文章带你全面了解

伴随着因特网的飞速发展&#xff0c;很多与因特网相关的职位都衍生出来了&#xff0c;UI 界面设计师是因特网的核心职位之一。UI 界面设计已经渗透到我们生活的各个方面&#xff0c;包括网站、应用程序或其它数字平台上的按钮、菜单布局、配色方案和排版等。很多人认为 UI 界面…

具有徊滞特性的欠压锁定功能的B3842/43/44是专为脱线和Dc-Dc开关电源应用设计的

B3842/43/44是专为脱线和Dc-Dc开关电源应用设计的恒频电流型Pwd控制器内部包含温度补偿精密基准、供精密占空比调节用的可调振荡器、高增益混放大器、电流传感比较器和适合作功率MOST驱动用的大电流推挽输出颇以及单周期徊滞式限流欠压锁定、死区可调、单脉冲计数拴锁等保护电路…

【Java程序设计】【C00369】基于(JavaWeb)Springboot的笔记记录分享平台(有论文)

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

BSV区块链的应用开发前景——通过标准化来促进创新

​​发表时间&#xff1a;2024年3月5日 近年来区块链领域的发展日新月异&#xff0c;各种全新的技术和方法论正在迅猛涌现。在这个瞬息万变的环境之中&#xff0c;标准化不仅仅会为开发者们带来便利&#xff0c;同时也促进了应用之间的互操作性&#xff0c;并且推动着生态系统的…

SAP ABAP-BOPF基础训练-01简介与架构

1. 介绍-Introduction ① BOPF是什么&#xff1f;BOPF(the Business Object Processing Framework)&#xff1a;业务对象处理框架 提供了一种增量和模块化的方法&#xff0c;以符合企业面向服务体系结构(eSOA)的方式实现业务对象&#xff1b; 部分平台基础层&#xff0c;软件组…

UI设计师必备软件:2024年趋势解读!

设计的两个关键方面是用户界面 (UI) 和用户体验 (UX)&#xff0c;UI设计侧重于人们如何与产品互动的审美元素&#xff0c;UX设计更侧重于人们如何使用产品&#xff0c;无论你的重点是什么 UX 还是 UI&#xff0c;或者你是否试图将两者结合起来&#xff0c;你需要高质量的UI设计…

【C++】share_ptr详解

一、share_ptr 的简单使用 1.1、基本用法 从较浅的层面看&#xff0c;智能指针是利用了一种叫做RAII&#xff08;资源获取即初始化&#xff09;的技术对普通的指针进行封装&#xff0c;这使得智能指针实质是一个对象&#xff0c;行为表现的却像一个指针。 智能指针的作用是防…

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

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

深入了解服务器硬件:从基础知识到实际应用

在当今数字化的社会中&#xff0c;服务器扮演着至关重要的角色&#xff0c;它们是支撑互联网、云计算、大数据等技术发展的基石。而理解服务器硬件的基础知识对于从事IT领域的人员来说至关重要。本文将从服务器硬件的基础知识出发&#xff0c;介绍服务器硬件的组成、作用及其在…

Python算法100例-4.3 多项式之和

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序 1&#xff0e;问题描述 计算下列多项式的值&#xff1a; 2&#xff0e;问题分析 方法一&#xff1a;把上面多项式中的每一个分项标上记号&#xff0c…