前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Java虚拟机相关八股一>jvm分区,类加载(双亲委派模型),GC

Java虚拟机相关八股一>jvm分区,类加载(双亲委派模型),GC

作者头像
用户11305962
发布2025-01-21 12:48:53
发布2025-01-21 12:48:53
860
举报
文章被收录于专栏:学习学习

一.jvm的分区:

jvm是仿照操作真实的系统设计的,主要仿照操作分区,也跟着分了很多区域  大致分部: sl

1.核心分区划分:    

注意: 类信息元:类叫什么名字,权限修饰限定符是什么public还是什么,继承哪些类,实现哪些接口。。  Java8之前元数据区,也叫方法区

1.1.程序计数器:很小的区域的一个内存空间,用来记录当前指令执行到哪个地址

1.2.元数据区:保存当前类被加载好的的数据(. class文件数据加载进来内存中),保存一些类对象 

1.3.栈:保存方法调用关系保存和局部变量(包括引用类型局部变量)  


1.4.堆:保存new的对象 eg: Test t = new Test (); t 是一个局部变量就在栈上  t 是一个成员变量就在堆上 t 是一个静态成员成员变量就在元数据区 

 注意:  元数据区和堆在整个Java进程中公用同一份 程序计数区和栈一个进程可能有好多份 (一个线程一份)  

二. jvm类加载: 

类加载本身是一个很复杂的问题,这里从Java官方文档和面试角度出发  

步骤: 1.)加载阶段:找到 .class文件 (根据类的全限定名 (包名+类名)eg:java.lang.String),找到打开文件,读取到内存里    

2.)验证阶段:解析校验.class文件内容是否合法,并把内容转换成结构化的数据

.class文件也有其格式: 


3.)准备:给类对象申请内存空间 (还没有填充只是申请) 


4.)解析:给字符串常量分配空间 

字符串常量本来就包含在 .class 文件中,通过.class 文件解析出来的字符串常量放到内存区(元数据区,常量池) 


5.)初始化:针对 3.)中的类对象初始化,如果这个类还有父类,会针对这个父类进行类加载 



三. 双亲委派模型: 

双亲委派模型其实就是整体从模块来说,如何进行类加载,jvm中有专门的模块进行类加载 jvm提供了三个类加载器来加载类:  1.BootstrapClassLoader : 负责记载java标准库目录 2.ExtensionClassLoader:负责加载Java扩展库的目录  3.AplicationClassLoader:负责加载Java第三方库/当前项目  


双亲委派模型加载步骤:  进行加载类的时候,先通过权限限定类名找到.class文件,会以AplicationClassLoader作为入口开始,AplicationClassLoader会委托给他的父亲ExtensionClassLoader来加载,然后 ExtensionClassLoader也会委托给他的父亲BootstrapClassLoader 来加载,BootstrapClassLoader 没有父亲,所以会从他开始从上往下进行找根据自己的库来查找 找不到会向下抛让他的孩子找,最后也没找到就会抛出异常 


总结:就是从下往上委托甩锅,然后从上往下开始找 



四.垃圾回收机制(GC):

1.为什么要有垃圾回收:  我们知道C语言中,申请内存空间->malloc 需要我们手动释放内存->free; 但是手动释放有时候会,忘记或者代码来不及释放(前面已经return), 导致内存泄漏; 所以Java中引入了垃圾回机制,来自动释放,jvm会自动帮我们完成。 


2.垃圾回收主要回收哪个内存区域?  GC主要回收jvm中的-> 堆内存区域  程序计数区,线程结束就会销毁,栈区方法栈帧结束就会销毁,元数据区的类对象一般不用销毁。 


3.垃圾回收的过程: 首先找到垃圾 (不在使用的对象),其次释放垃圾(对应的内存释放掉)    找垃圾的方式有两种 :引用计数,和可达性分析(JAVA采用的方式)


3.1.引用计数:  主要是python和PHP采用的回收机制,每个对象在new的时候,会搭配一个小的内存空间来计数指向这个对象的引用个数,如果引用个数为0,表示这个对象不在使用,就GC 

缺点:  首先内存消耗过多,其次会出现循环引用的问题   


循环引用就是:两个对象的引用相互指向,两个对象的引用被释放后,两个对象的引用计数却不为0,但是也没有引用来使用这两个对象了 


3.2.可达性分析(JAVA采用的方式):  以代码中的一些特定对象作为遍历的起点,(栈上局部变量的引用,常量池引用指向的对象,静态成员变量的引用) ,尽可能的遍历判断某个对象是否访问到,每次访问到一个对象都会把这个对象标记成可达,未标记成可达的对象就是不可达  

这里遍历到一个节点就标记为可达,如果某一个断开了后面的引用就不可达,有点像树的遍历,深度优先遍历 


可达性优缺点: 优点:有点就是不会出现出现循环引用问题; 缺点:但是遍历需要的时间开销还是很大的 

4. 释放垃圾:  Java中的垃圾回收是通过:标记-清除,复制算法,标记-整理三种方法结合“分代回收”综合进行GC。


4.1.标记-清除:  把垃圾对象的内存直接进行释放 


缺点:会产生内存碎片化问题   内存碎片化问题,就是空闲空间东一点西一点,可能会导致下次申请空间失败


4.2.复制算法:  一次只使用其中的一半,把不是垃圾的对象拷贝到一侧,垃圾对象一侧回收掉  


缺点:虽然不会出现内存碎片,但是内存空间利用率很低;如果对象很大很多复制成本很高可能无法进行 


4.3.标记-整理: 让所有不是垃圾的对象都向一端移动,然后直接清理掉端边界以外的内存。类似顺序表的搬运 


缺点:虽然解决了内存碎片化还保证了空间利用概,但是类似顺序表的搬运还是有很大成本 


4.4.分代回收:  分代算法是通过区域划分,实现不同区域和不同的垃圾回收策略从而实现更好的垃圾回收  根据对象存活不同的年龄,进行不同的回收。也会结合以上三种回收算法来进行回收



新生代可以GC频率高一点,老年代GC频率低一点; 老年代一般会进行标记-整理算法, 新生代复制算法。 

一个对象经历的过程: 在新生代中,伊甸区如果没有被GC,会到幸村区,在幸村区也会经过多次GC,还存活着就到老年代,类似我们投递简历,前面大片被刷,经过多次笔试,面试存活下来拿到offer! 

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.jvm的分区:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档