生产环境JVM调优
- 关系型数据库到达瓶颈。索引、分布式缓存、分库分表
- 扩容。横向、纵向扩容。
- 代码。资源浪费、逻辑优化、并行处理
- JVM优化。是否存在多次GC
-
调优JVM
在【理解】JVM内存结构以及各种垃圾收集器的前提下,结合现有业务来【调整参数】,使自己的应用平稳运行。
内存区域大小及相关的策略。(xmx、xms、xmn、XX:SurvivorRatio)IO密集型可以调大些【年轻代】
垃圾回收器。(合适的垃圾回收器、回收器的调优参数)G1可以设定目标停顿时间 全局并发标记启动的堆内存比例
利用工具进行排查
jps查看Java进程号
- jstat查看Java进程【统计类】相关信息(类加载、编译相关、各个内存区域GC情况)
- jinfo查看调整Java进程的【运行参数】
- jmap查看Java进程【内存信息】,dump堆用MAT分析文件
- jstack查看JVM【线程信息】,排查死锁问题
- Arthas
在【解释】阶段,有两种方式把字节码信息解释成指令码,一个是字节码解释器,一个是即使编译器(JIT)
JIT优化技术(不同的JVM版本堆JIT优化不太相同)
- 方法内联。把【目标方法】的代码复制到【调用的方法】中,避免发生真实的方法调用。(方法调用会生成栈帧,JVM有相关参数指定XX:MaxInlineSize)
- 逃逸分析。判断一个对象是否被外部方法引用,若不被引用,进行优化。锁消除、栈上分配(对象直接在栈上分配,快)、标量替换/分离对象(不创建对象,而是创建成员变量,对象无需分配内存空间)。
GC主要工作在Heap区和MetaSpace区,在DirectMemory中,如果使用的是带Cleaner的DirectByteBuffer,GC可以通过 Cleaner间接管理。
引用计数算法处理循环引用问题,需要进行昂贵的同步操作,性能较低。
分配对象
Java对象地址操作会主要使用Unsafe调用C的allocate和free两个方法。
- 空闲链表。额外的存储记录空闲的地址,将随机IO变成顺序IO,但带来了额外的空间消耗。
- 碰撞指针。通过一个指针作为分界点,需要分配内存,仅需要把指针移动与大小相等的距离,但使用场景有限。