目标
- 熟悉GC常用算法,熟悉常见垃圾收集器,具有实际JVM调优实战经验
组成
- 类装载子系统
- 运行时数据区(内存模型)
- 字节码执行引擎
内存区域
- 堆
- 存放new出来的对象
- 所有线程和方法共享
- 栈(线程栈)
- JVM为每个线程分配一个独立的栈空间,存储局部变量
- 栈帧:每个方法对应一块栈帧,存放方法的局部变量,方法运行完销毁
- 局部变量表:为变量分配内存空间,变量指向堆中的对象(地址)
- 操作数栈:存放临时数据
- 动态链接:实现多态
- 方法出口:调用函数后返回原位置继续执行
- 本地方法栈:本地c语言写的方法在运行过程中需要的运行空间,为调用本地方法的线程分配
- 程序计数器(pc Register):线程正在运行的代码的行号,每个线程独有,实现多线程
- 方法区(元空间)
- 常量
- 静态变量(static)
- 类信息
gc(Garbage Collect)
- 垃圾:没有引用指向的对象
- C++:new(),delete(),自己清理垃圾
- 找垃圾算法
- reference count(引用计数):不能解决环形引用
- root searching(根可达算法)
- 从gc root出发,向下搜索引用的对象,找到的对象标记为非垃圾对象
- 存入S0区,并回收Eden中的对象
- 哪些是根
- JVM stack
- native method stack
- run time constant pool
- static reference in method area
- Clazz
- 回收算法
- Mark-Sweep(标记清除):会产生碎片
- Copying:内存浪费
- Mark-Compact:需移动对象,效率比Copying低
- 发展路线
- 随着内存增大而演进(先脉络,后细节)
- 从分代算法演化到不分带算法
- hotspot
- 工作在年轻代的GC
- Serial:a stop-the-world(STW), copying collector which uses a single GC thread(几M~几十M)
- ParNew:PS,可配合CMS
- Parallel Scavenge:a STW, copying collector which uses multiple GC threads(几个G,1.8默认)
- 工作在老年代的GC
- CMS:初始标记(STW,找gc root,快)->并发标记(不用STW,慢)->重新标记(STW,快)->并发清理(承上启下,三色标记+写屏障,几十个G)
- Seril Old:STW,single GC thread,用 mark-sweep 或 Mark-Compact
- Parallel Old(1.8默认 PS + PO/Parallel GC,几百个参数)
- G1
- Garbage First(先清理垃圾多的块,几十个参数)
- 逻辑分代,物理不分代(上百G)
- 分区回收
- 三色标记+SATB+写屏障
- ZGC Shenandoah
- 逻辑,物理都不分代(4T)
- 基于C4(None STW)
- ColoredPointers,颜色指针+读屏障
- Epsilon
- 调试,确认不用GC参与就能干完活
- 工作在年轻代的GC
- 分区算法
- 80%对象“朝生夕死”
- 找出eden区的幸存对象,复制到s0,清除剩余对象
- 找出eden区、s0区的幸存对象,复制到s1,清除剩余对象
- s0,s1互换,重复上一步
- 15次(不同GC不一样)不死的对象,复制到老年区(如缓存对象,spring中的bean等)
- 老年区满,full gc,整体回收
- 概念
- YGC:minor gc
- FGC:full gc,major gc
- TLAB:thread local allocation buffer,每个线程专属的内存空间,属于eden
- 标记失误:垃圾在标记后,清除前被引用
- 分代年龄:放在对象头中,每次minor gc后没有被清除,分代年龄+1
- 对象头(Object Header):并发编程、JVM基础
- 类装载子系统:装载类到本地方法栈
- 字节码执行引擎:修改程序计数器,执行方法区中的class文件
CMS
G1
调优
- 目的: 减少STW(Stop The World),即JVM触发full gc会暂停所有其他线程,造成卡顿
- STW的目的:线程停止后,gc root可能消失,导致原来不是垃圾的对象变成垃圾对象
- 对象动态年龄判断机制
- 手段
- 调吞吐量
- 调响应时间
- OOM(out of memory):如何通过调优解决
实例1
- 8G内存,degn
- 每日用户点击量上亿
- 日活500w左右
- 京东、拼多多等
- 每秒几十单
- 大促时80%的订单在几分钟产生
- 每秒1000多单
- 每个订单对象1KB
- 每秒300KB订单对象
- 下单涉及其它对象,如库存,优惠券,积分等,再放大20倍
- 6M/s对象放入堆中
- 其他操作再放大10倍
- 60M/s对象放入eden,1s后都变成垃圾()
- 10s放满
- gc root:
- old区几分钟放满,执行full gc,1s后变成垃圾(不应该放在old)
- 将eden调为1.6G,25s填满
- 调优后,不会发生full gc
调优前
调优后
实例2
中间件性能调优
工具
- arthas
参考
- javap-c:反汇编
- JVM指令手册