1.类初始化过程:
classloading (加载)
classlinking verification(验证,验证文件是否符合JVM规定) -> preparation(准备,静态变量赋默认值) ->Resolution(解析,将类、方法、属性等符号引用解析为直接引用)
class initialization (初始化,静态变量初始化)
2.对象初始化:
申请对象内存 -> 成员变量赋默认值 ->调用构造方法 (成员变量赋初始值)
3.类加载器:
BootStrap classloader lib/rt.jar 加载核心类库
Extend classloader ext 扩展类库
Application classloader classpath目录下的类
Custom classloader 自定义类加载器 (extends ClassLoader, 重写findClass方法,返回defineClass(byte[] -> Class clazz))
4.双亲委派机制:
孩子向父亲方向,然后父亲向孩子方向的过程
1.避免类的重新加载,已经加载过的类没必要重新加载
2.防止核心API库被随意篡改,如java.lang.String
5.懒加载lazyloading
JVM规范没有规定什么时候加载,但是规定什么时候进行初始化。
子类初始化时候先初始化父类
6.垃圾回收算法和垃圾定位
C,C++ 都要手动回收垃圾,弊端忘记回收内存溢出,重复回收。Java自动垃圾回收机制
垃圾定位:引用计数(referencecount),根可达算法(root searching)
垃圾回收算法:标记清除(扫描两遍,有碎片),拷贝算法(浪费空间,没碎片)
7.内存分代模型
-
部分垃圾回收器使用的模型
除Epsilon ZGC Shenandoah之外的GC都是使用逻辑分代模型
G1是逻辑分代,物理不分代
除此之外不仅逻辑分代,而且物理分代
-
新生代 + 老年代 + 永久代(1.7)Perm Generation/ 元数据区(1.8) Metaspace
- 永久代 元数据 - Class
- 永久代必须指定大小限制 ,元数据可以设置,也可以不设置,无上限(受限于物理内存)
- 字符串常量 1.7 - 永久代,1.8 - 堆
- MethodArea逻辑概念 - 永久代、元数据
-
新生代 = Eden + 2个suvivor区
- YGC回收之后,大多数的对象会被回收,活着的进入s0
- 再次YGC,活着的对象eden + s0 -> s1
- 再次YGC,eden + s1 -> s0
- 年龄足够 -> 老年代 (15 CMS 6)
- s区装不下 -> 老年代
-
老年代
- 顽固分子
- 老年代满了FGC Full GC
-
GC Tuning (Generation)
- 尽量减少FGC
- MinorGC = YGC
- MajorGC = FGC
8.垃圾回收器
不同的垃圾回收器配合不同的内存使用,内存越大扫描的空间越多,要配合不同的垃圾回收器
Serial + Serial old(几十兆内存),串行垃圾回收,只有一个线程回收垃圾,效率低
Parallel Scavenge + Parallel Old(几百兆-几个G),多个线程对垃圾进行回收,默认垃圾回收器
PartNew + CMS(20G以上)
G1(上百G)
ZGC(T级别)
9.为什么要调优
- 根据需求进行JVM规划和预调优
- 优化运行JVM运行环境(慢,卡顿)
- 解决JVM运行过程中出现的各种问题(OOM)
10.调优
-
调优,从业务场景开始,没有业务场景的调优都是耍流氓
-
无监控(压力测试,能看到结果),不调优
-
步骤:
- 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
- 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
- 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
- 选择回收器组合
- 计算内存需求(经验值 1.5G 16G)
- 选定CPU(越高越好)
- 设定年代大小、升级年龄
- 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
11.案例
- 有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G
的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G
的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了- 为什么原网站慢?
很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢 - 为什么会更卡顿?
内存越大,FGC时间越长 - 咋办?
PS -> PN + CMS 或者 G1
- 为什么原网站慢?
- 系统CPU经常100%,如何调优?(面试高频)
CPU100%那么一定有线程在占用系统资源,- 找出哪个进程cpu高(top)
- 该进程中的哪个线程cpu高(top -Hp)
- 导出该线程的堆栈 (jstack)
- 查找哪个方法(栈帧)消耗时间 (jstack)
- 工作线程占比高 | 垃圾回收线程占比高
- 系统内存飙高,如何查找问题?(面试高频)
- 导出堆内存 (jmap)
- 分析 (jhat jvisualvm mat jprofiler … )
- 如何监控JVM
- jstat jvisualvm jprofiler arthas top…