jvm面试总结
类加载机制?
如何把类加载到jvm中 ?
装载–>链接–>初始化–>使用–>卸载
-
装载:
- ClassFile–>字节流–>类加载器
- 将字节流所代表的静态结构转化为方法区的运行时数据结构
- 在我们的堆中生成一个代表这个类的java.lang.Class对象
-
链接:
-
验证–4种验证:
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
-
准备
-
为类的静态变量分配内存,并赋值(当前类型的默认值).
例如: private static String a; 不进行改动,直接打印,null,给String a 赋值 null
-
-
解析
-
解析是从运行时常量池中的符号引用动态确定具体值的过程
-
符号引用转换为直接引用
例如:有些符合是不需要开辟空间,从新生成的.直接转换即可
-
-
-
初始化
- 方法执行到了Clinit阶段,初始化静态变量的值,初始化静态代码块,初始化当前类的父类
类加载器有哪些?
4种类加载器
Bootstrap ClassLoader
Extension ClassLoader Person
App ClassLoader
Custom ClassLoader
双亲委派机制(父类委托机制)
从下往上委托.从上往下找
如何打破双亲委派机制?
- 复写
- SPI(Service Provider Interface 服务提供接口) 拓展性强,
- 有时我的需求并不能满足厂商,需要实现接口,走我的实现方法
- OSGI 热部署,热更新,整体模块
运行时数据区
橘黄部分:线程共享:堆 方法区
蓝色部分:线程私有:程序计数器,本地方法栈,JAVA虚拟机栈
栈帧结构
栈帧
是Java虚拟机最小存储单元
局部变量表:方法中的局部变量以及方法的参数会存放在这
操作数栈:也是一个栈,他是以压栈以及出栈的方式来存储操作数的
int a = 1;
int b = 1 ;
int c = a + b;
方法的返回地址: 一个方法执行之后,只有两种情况可以退出,遇到返回的字节码指令 异常返回
动态链接:动态链接将这些符号方法引用转换为具体的方法引用 符号引用转化成直接引用
void a(){
b();
}
void b(){
c();
}
void c(){}
堆 为什么 分代设计?
问:为什么要这么设计?
答:
从一块整区域清除垃圾,分为新生代(Young),循环15次进入,老年代(old)
young区中再分,新生区(Eden),幸存区(Survivor)
Young GC 从(Eden区)活过一次的放入幸存区(Survivor)
S区接着分,两个S区,来回腾挪,清空另一个.(Survivor 0,Survivor 1)
问: Eden区 80M,S区10M x 2,Old200M,这是时候有个90M的对象,放哪里?
答: 担保机制,90M直接进入Old区,大对象的产生,是一种灾难.会导致 Full GC
分区比例 Eden:S0:S1是8:1:1,为什么?
答:
Eden不够用会触发 Young GC;(GC不是好事情,也会占用资源)
Eden区越小,GC约多.
官方推荐:Eden 80M(需要结合项目)
什么是Full GC?
堆,非堆的垃圾回收机制
垃圾回收算法
引用计数法
引用计数法 循环引用 会导致内存泄露, 内存泄漏的堆积会导致内存溢出
可达性份分析算法 从一个名叫 根 的位置出发,衍生一条引用链,搜索这条链条上的所有对象
(什么是GC ROOT 静态变量,常量,栈帧中的局部变量表中的元素 作为根)
(GC ROOT 根对象 错误!!! 本质是一组活跃的指针 )
(若:GC 判定为不可达对象,那么该对象就死刑吗? 不是 )
标记清除法
- 不该回收的,回收了
- 该回收的,没回收
串行 Stop the world(GC运行时,任何业务线程无法运行,业务线程卡顿)
判断GC 好坏, 卡顿时间
复制算法
标记清除整理算法
标记 清除 整理算法 标记压缩算法
随机整理 线性整理 滑动整理
分代收集算法
新生代: 复制算法
老年代: 标记清除 或 标记整理