[Java] JVM

 目标

  • 熟悉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参与就能干完活
  • 分区算法
    • 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指令手册
原文地址:https://www.cnblogs.com/cxc1357/p/12521570.html