【笔记】深入理解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,它可以帮助我们解释我们为什么可以通过嵌套方法,共享数据,以及为什么可以在函数中定义一个和全局变量同名的变量,并且不会影响到全局变量。 基本分析 基本概念…

28377s使用的记录和注意点(1)

28377s使用的记录和注意点(1)_dsp28377设置复位不清除ram区域-CSDN博客

SUB-1G替代CMT2380F32 SOC芯片DP4306F 32 位ARM Cortex-M0+内核应用无线遥控工控设备智能家居

DP4306F是一款高性能低功耗的单片集成收发机,集成MO核MCU,工作频率可覆盖200MHiz^ 1000MHz。 支持230/408/433/470/868/915频段。该芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK解调器等功能模块。通过SPI接口可以对输出功率、频道选…

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

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

几个常用的AI工具

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

面向对象【枚举类】

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

spring maven项目 实时接口请求次数及时间发送到grafana监控_亲测成功

spring maven项目 实时接口请求次数及时间发送到grafana监控_亲测成功 说明: spring项目使用aop方式拿到请求接口uri,算出从请求到响应的耗时, 然后使用statsd包发送udp数据给grafana去展示. 完全不影响代码性能和稳定性,因为使用udp协议发送,就算grafana那边挂了,也不影响项…

【C++】6-2 交换函数2 分数 10

6-2 交换函数2 分数 10 全屏浏览 切换布局 作者 刘利 单位 惠州学院 根据题目需求&#xff0c;编写一个交换函数Swap。 裁判测试程序样例&#xff1a; #include <iostream> using namespace std; class pen{private:string brand;string color;double price;publi…

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

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

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

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

OJ : 1090 :整数幂(多实例测试)

题目描述 求A^B的最后三位数表示的整数&#xff08;1<A,B<1000&#xff09; 输入 n个测试实例&#xff0c;每个实例给出两个正整数A,B 输出 输出A^B的最后三位&#xff08;没有前导0&#xff09; 样例输入 2 2 3 12 6 样例输出 8 984 思路&#xff1a; 这个题…

c# 更改网卡的默认网关

前言: 通过程序更改网卡网关 公司内有多个网络出口,其中一个为固定IP的 带宽只有60M用于应用系统访问, 一个是一条千兆带宽的ADSL,但是只有电信内网IP。做开发调试尤其是企业微信接口涉及到接口白名单IP&#xff0c;需要走固定IP&#xff0c;而日常一些下载当然我选择用千兆带宽…

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

简介 每次打开页面视频从上一次的播放位置开始播放 利用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驱动用的大电流推挽输出颇以及单周期徊滞式限流欠压锁定、死区可调、单脉冲计数拴锁等保护电路…

Oracle 去除重复记录SQL

在Oracle数据库中&#xff0c;可以使用DELETE语句删除多个表中的数据&#xff0c;也可以使用INNER JOIN、LEFT JOIN、RIGHT JOIN等连接操作来删除多个表中的数据。 下面是一些示例&#xff1a; 删除两个表中相同的记录 DELETE FROM table1 WHERE EXISTS (SELECT 1 FROM table2…

公历农历干支互转

日历描写的是地球上观星的规律 公历&#xff08;阳历&#xff1a;太阳历&#xff09;、农历&#xff08;阴历&#xff1a;月亮历&#xff09;互转 1.1900-2100农历的润大小信息表 农历一年有多少天&#xff1f; 农历一年通常是354天或355天&#xff0c;但有时也会出现384天或…