浅入理解JVM虚拟机
1. 类加载过程
验证 —— 准备 —— 解析 —— 初始化
验证阶段: 判断.class文件符合规范标准
准备阶段:给类以及静态变量分配内存并给初始值 “0”
解析阶段: 维护哥哥字段,方法类的内存指针或偏移量
初始化阶段: 变量赋值(真实的值),执行代码
什么时候一个类会进行初始化阶段?
1.new一个实例化对象时
2.包含main方法的主类
3.需要初始化子类时,必须先初始化父类
2. Tomcat如何实现热部署?
类加载器与双亲委派机制
启动类加载器 —— 扩展类加载器 —— 应用类加载器 —— 自定义类加载器
双亲委派机制也就是拿到一个类,先交给他的父类加载器加载,一层一层传递,如果都加载不了再回到自己的加载器加载,
这样就保证了每个类都会尽可能的在最上层加载器加载,且只会加载一次。保证了沙箱安全
Tomcat的实现方式
第一种,在WEB-INFO/class 目录下的文件,使用WebApp类加载器
启用一个线程来检测class文件的modify时间是否发生变化,如果发生变化就时1开关reloadable = true,使整个容器重启,全部重新加载
第二种,jsp类文件使用Jsp类加载器加载,Jsp类加载器属于一次性的
当jsp文件每次被修改时,都会使用一个新的Jsp类加载器加载。每此都会有新的jsp加载到jvm,并丢弃上一个
3. 垃圾回收器与垃圾回收算法
1.复制算法,用于新生代,Eden区与s1区中存活对象复制到s2区,剩下对象干掉
优点:不会产生内存碎片 缺点: 始终浪费一块空间
2.标记清除算法,用于老年代,先标记出哪些是垃圾,再统一清理
优点:节省空间 缺点:容易产生内存碎片
3.标记整理算法,用于老年代,就是在标记清除的基础上加一次整理,把内存碎片干掉
缺点:耗时
ParNew垃圾回收器,用于新生代,支持多线程,STW
CMS垃圾回收器,用于老年代,四个阶段 初始标记(标记GCRoot直接引用对象) —— 并发标记(GCRoot间接引用对象) —— 再次标记(补充并发标记中创建的对象) —— 并发清除
其中初始标记和再次标记是STW的,也占用的时间比较短
CMS采用标记清除,可配置JVM参数,多少次标记清除后一次标记整理
4. 关于GCRoot
用作可达性分析的根,一般是类静态变量和栈中的局部变量的对象
finalize()方法,
GC前会调用该对象的finallize()方法,试图抢救一下。所以可以在该方法中将当前对象挂上GCRoot链路,避免被回收
finalize 方法只会被执行一次,如果第一次执行 finalize 方法此对象变成了可达确实不会回收,但如果对象再次被 GC,则会忽略 finalize 方法,对象会被回收!
5. 关于方法区
方法区属于概念,jdk1.8之前是永久代实现(与堆内存连续的),之后是元空间实现(在JVM外的本地内存)
方法区存的是类的模板,动态生成的类,静态变量,常量池(注意1.8以后常量池物理上存在于堆内存,但是逻辑上还是属于方法区的,咱也不懂)
方法区发生回收需要满足的条件
1.该类的所有实例对象都已经被JVM回收
2.加载该类的类加载器被回收
3.该类的Class对象没有任何引用
(个人感觉这些条件如此苛刻,因此方法区溢出导致的FullGC大概率并不会导致方法去回收,从而导致无限的FullGC)
对象进入老年代的几种情况(如何避免进入老年代)
发生FullGC的几种情况
Java服务CPU打满的几种情况
GC调优的思路
GC调优工具
JVM调优案例分析