首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
SAAS
ToB门户
了解全球最新的ToB事件
论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
微博
Follow
记录
Doing
博客
Blog
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
排行榜
Ranklist
相册
Album
应用中心
qidao123.com技术社区-IT企服评测·应用市场
»
论坛
›
大数据
›
数据仓库与分析
›
JVM先容
返回列表
发新帖
JVM先容
[复制链接]
发表于 2025-10-16 10:30:51
|
显示全部楼层
|
阅读模式
一.JVM内存地域分别
1.内存地域先容
1)步伐计数器(比力小的空间)
生存了下一条要实行指令的所在。此处的步伐计数器不再是CPU的寄存器了,而是内存空间。而且,此处的下一条要实行的指令是Java的字节码(不是CPU的二进制的呆板语言)
2)堆
JVM上最大的空间,new出来的对象都在堆上。
3)栈
函数中的局部变量,函数的形参,函数之间的调用关系。
Java假造极栈:JVM之上运行的Java
代码
的方法调用关系
本地方法栈:JVM里头,C++
代码
的函数调用关系。
4)元数据区(方法区)
Java步伐中的指令(指令都包罗在类的方法中)
生存了
代码
中涉及到的类干系的信息
类的static属性
在一个Java历程中,元数据区和堆是只有一份的(同一个历程中的全部线程都是共用一份数据的),步伐计数器和栈大概有多份,当一个Java历程中有多个线程的时间,每个线程都有本身的步伐计数器和栈
线程就代表一个实行流,每个线程就须要生存本身的步伐计数器,每个线程也须要记载本身的调用关系。
2.代码中变量位于的地域
类似于如许一段的代码,须要明确此中变量存在于JVM内存地域的哪个地域。一个变量处于哪个内存地域,这个和变量是不是“内置范例”无关,而是和变量的形态有关。
(1)局部变量:栈
(2)成员变量:堆
(3)静态成员变量:元数据区(方法区)
a,b都是成员变量,均在堆区。
c,d是静态成员变量,均在元数据区(d是new了一个对象,new出来的对象是在堆区,但是把这个堆上的内存所在,赋值给了d引用范例的变量)
e,f都是局部变量,均在栈区(f也是new了一个对象, new出来的对象仍旧在堆区,但是把这个堆上的内存所在,赋值给了这个f变量)
二.JVM类加载的过程
运行java历程的时间,JVM就须要读取 .class中的内容,而且实行内里的指令(读取 .class中的内容就是类加载,把类涉及到的字节码从硬盘读取到内存中(元数据区),把这个 .class 中的指令转换成类对象)
加载一个 .class文件,就会对应创建一个类对象,类对象就包罗了 .class文件中的各种信息(比如:类名,类的属性和方法,继承的父类,实现的接口等等······)也就阐明类对象就是对象的阐明书/蓝本
1.类加载的具体步调
类加载分为五个环节,也可以分为三个环节,无论是那种都是对的,只是一些环节被归为一类而已,此处说的是五个环节
(1)加载
把 .class 文件找到,代码中先见到类的名字,然后进一步的找到对应的 .class 文件(涉及到一系列目次查找的过程)找到后,
打开并读取文件内容
(2)验证
验证读到的 .class 文件的数据是否准确与正当,在Java标准
文档
中,明确界说了 .class 文件的格式是怎么样的
u4:4个字节的unsigned int,u2:2个字节的unsigned short这是在Java中的,c++则不愿定,c++会由于差异的利用体系和编译器导致l同范例的字节数差异。
magic:魔幻数字,在二进制文件中的开头,有多少个字节,设置一个固定的常数进去,通过这个常数,标识当前这个文件是什么样的文件
minor_version和major_version:确保编译和运行时的JDK
版本
同等
constant_pool_count:常量池
cp_info:其他结构体
access_flags,this_class,super_class:代表这个类是public还是其他的修饰词,后续代表的是类和父类
fields_count ,fields[fields_count]:代表类中的属性
反面的都代表类中的方法
(3)分配内存空间
根据刚才读取到的内容,确定出类对象须要的内存空间,再申请如许的内存空间,而且把内存空间中的全部内容,都初始化为0(Java创建一个内存空间,都会把这个内存空间全部设置为0,后续再进一步的初始化)
类加载实行到第三步时,此时a的值还为0
(4)剖析
重要针对类中的字符串常量举行处理处罚,剖析阶段是Java假造机将常量池内的符号引用更换为直接引用的过程,也就是初始化常量的过程。
直接引用:平常谈到的代码中的引用,内里也生存了变量的所在。
符号引用:字符串常量,已经在 .class 文件中。
“hello”字符串常量,已经在 .class 文件中了,但是没有所在如许的概念,此时所在的概念就是内存的所在,取而代之的是,类似于文件偏移量的概念。
符号引用和直接引用图解:
(5)初始化
针对类对象做终极的初始化利用,实行静态成员的赋值语句。
实行类中的静态代码块,针对父类也要举行加载,在这个环节也会触发对父类的举行加载(实行上述的五个环节)
2.双亲委派模子
(1)双亲委派模子先容
是类加载五个步调中,第一个步调内里的一个环节,给定 类全限定名,找到对应的class文件位置。
类加载器JVM中,已经内置了一些加载器,完成上述的内加载过程
JVM默认有三个类加载器:
不是Java父类子类的继承关系,而是类加载器中有一个parent如许的引用指向父亲
(2)工作流程
图解:
如许做的核心目的:
防止用户本身写的类,把标准库的类给覆盖了
包管标准库的类,被加载的优先级是最高的
扩展库其次,第三方库的优先级最低
三.JVM的垃圾接纳机制(GC)
1.须要接纳的内存地域
JVM中的内存地域的步伐计数器和栈是不须要GC的,由于它们会跟随线程一起烧毁。而堆是GC重要接纳的地方,堆上new的对象就须要GC判定是否须要接纳。元数据区中的类对象的类加载是有上限的,不会出现无穷增长的情况,一样平常不须要GC。
堆的分区
2.接纳机制实现
(1)找出“垃圾”
须要针对每个对象举行判定是否为“垃圾”,在Java中利用一个对象,一样平常都是通过引用来利用的,假如一个对象没有引用指向了,都可以以为这个对象是“垃圾”了。
i.引用计数器
给每个对象分配一个计数器,衡量有多少个引用指向,每次增长一个引用,计数器+1,每次淘汰一个引用计数器-1,当计数器减为0时,此时对象就是“垃圾”了(多线程的可重入锁也是类似的机制)
图解计数器:
第一步
第二步
第三步
第四步
如许的方案在Java中并没有接纳,而是python和PHP举行了利用
上述方案存在两个题目:
1.斲丧了额外的空间(假设Test类就只有一个int成员(4个字节),此时为了引入计数器,最少也要一个short(2个字节),内存就多占用了50%)
2.引入计数器大概导致“循环引用”使得上述的判定堕落
第一步
第二步
第三步
这两个对象的引用计数都不是0,不能被开释,但是这两个对象又无法被利用,就造成了类似于死锁的场景。循环引用也是有解的,须要引入更多的机制(环路检测)代价就更大了。
ii.可达性分析(Java接纳的方案)
在JVM中,专门搞了一些周期性的线程,扫描代码中全部的对象,判定某个对象是否是“可达”(可以被访问到),对应的,不可达的对象就是垃圾了。
1)JVM有一个全部对象的总名单
2)JVM针对当前课堂内里的对象举行点名利用(被点到的,答复到),没有答复到的,就是旷课的(也就是“垃圾”)
通过类似于二叉树的结构,获取到根节点,就可以对整个树举行遍历,遍历就可以或许得到每一个节点的对象,此时这些对象都是可
达的。假如此时根节点的右节点为null,则为不可达。
类似于如许的树结构,当c不可达时,f也是不可达的,此时的f的可达性依靠于c的可达性。
可达性分析的出发点称为GC root,一个步伐中,GC root不是只有一个,而是有许多(栈上的局部变量(引用范例),方法去中,静态的成员变量(引用范例),常量池引用指向的对象,这三个GC root)
可达性分析,实在是挺斲丧时间的,尤其是你的步伐中,对象特别多的情况下,就须要许多时间。
(2)开释“垃圾”的内存空间
1.标志- 扫除
直接针对内存中对应的对象举行开释
但是上述的做法会引入“内存碎片题目”,对象的开释是随机的,很大概开释的这个内存不是一连的,固然把上述的内存开释掉了,但是团体这些空闲内存并没有连在一起,后续申请内存的时间,就无法申请(申请的内存必须是一连的)
2.复制算法
将一块内存分成两块,同一时间,只利用此中的一半,当开释垃圾之前,把不是垃圾的对象拷贝到另一半中(确保拷贝的对象是一连的)然后把须要开释垃圾的这一半的空间都是开释了
第一步
第二步
但是复制算法的缺点也很显着:内存空间利用率太低了;假如存活下来的对象比力多,复制的资本也比力大。
3.标志-整理
非常类似于,次序表删除中心的元素。
第一步
第二步
但是像如许举行搬运的开销也不小。
4.分代接纳
JVM中真实的办理方案,是把上述几个方案综合一下,取长补短,也就转换成了分代接纳
JVM根据对象的年龄(可达性分析,周期性的每次颠末一轮扫描,对象仍旧存活(不是垃圾)年龄+1),把对象举行区分
新创建的对象
存储
在伊甸区,根据履历规律,绝大部门的新对象,活不外第一轮GC,留存下来的对象,拷贝到幸存区。
幸存区是两个相称的空间,也是按照复制算法(反复举行多次在幸存者区的两个内存空间中来回举行复制,只要通过GC的磨练,就可以或许存活下来)
新生代中,真正要拷贝的对象不多(履历规律),但是内存利用率低(幸存区中的另一个内存就会被浪费,但是幸存区的内存空间比力小,以是不要紧)
假如一个对象在幸存区,已经反复被拷贝多次,也不是垃圾,年龄则会不停增长,到达肯定程度后,对象就要被拷贝到老年代了。
根据履历规律,老年代中的对象的生命周期都会比力长,老年代的对象固然也须要举行可达性分析,但是老年代举行GC的频率就会低沉,别的,老年代也是通过标志整理(须要整理的次数也不多)
3.其他的垃圾接纳器
分代接纳时JVM中GC的根本头脑方法,具体落实到JVM的实现层上,JVM还提供了多种“垃圾接纳器”(对上述的分代接纳,做进一步的扩充和具体实现)
重点相识CMS和G1
CMS:
G1:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
×
回复
使用道具
举报
返回列表
九天猎人
+ 我要发帖
×
登录参与点评抽奖,加入IT实名职场社区
去登录
微信订阅号
微信服务号
微信客服(加群)
H5
小程序
快速回复
返回顶部
返回列表