Java虚拟机相关八股一>jvm分区,类加载(双亲委派模型),GC
目录:
一.jvm的分区:
二. jvm类加载:
三. 双亲委派模型:
四.垃圾回收机制(GC):
一.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!