生产环境JVM调优

  1. 关系型数据库到达瓶颈。索引、分布式缓存、分库分表
  2. 扩容。横向、纵向扩容。
  3. 代码。资源浪费、逻辑优化、并行处理
  4. JVM优化。是否存在多次GC
  5. 网络和操作系统排查。内存、CPU、网络、硬盘读写指标。

    调优JVM

    在【理解】JVM内存结构以及各种垃圾收集器的前提下,结合现有业务来【调整参数】,使自己的应用平稳运行。

  6. 内存区域大小及相关的策略。(xmx、xms、xmn、XX:SurvivorRatio)IO密集型可以调大些【年轻代】

  7. 垃圾回收器。(合适的垃圾回收器、回收器的调优参数)G1可以设定目标停顿时间 全局并发标记启动的堆内存比例

    利用工具进行排查

  8. jps查看Java进程号

  9. jstat查看Java进程【统计类】相关信息(类加载、编译相关、各个内存区域GC情况)
  10. jinfo查看调整Java进程的【运行参数】
  11. jmap查看Java进程【内存信息】,dump堆用MAT分析文件
  12. jstack查看JVM【线程信息】,排查死锁问题
  13. Arthas

在【解释】阶段,有两种方式把字节码信息解释成指令码,一个是字节码解释器,一个是即使编译器(JIT)
JIT优化技术(不同的JVM版本堆JIT优化不太相同)

  1. 方法内联。把【目标方法】的代码复制到【调用的方法】中,避免发生真实的方法调用。(方法调用会生成栈帧,JVM有相关参数指定XX:MaxInlineSize)
  2. 逃逸分析。判断一个对象是否被外部方法引用,若不被引用,进行优化。锁消除、栈上分配(对象直接在栈上分配,快)、标量替换/分离对象(不创建对象,而是创建成员变量,对象无需分配内存空间)。

GC主要工作在Heap区和MetaSpace区,在DirectMemory中,如果使用的是带Cleaner的DirectByteBuffer,GC可以通过 Cleaner间接管理。
引用计数算法处理循环引用问题,需要进行昂贵的同步操作,性能较低。

分配对象

Java对象地址操作会主要使用Unsafe调用C的allocate和free两个方法。

  1. 空闲链表。额外的存储记录空闲的地址,将随机IO变成顺序IO,但带来了额外的空间消耗。
  2. 碰撞指针。通过一个指针作为分界点,需要分配内存,仅需要把指针移动与大小相等的距离,但使用场景有限。