JVM调优
JVM调优
-
单机大内存一个JVM,大内存会导致FULL GC停顿时间太长
-
使用若干个JVM建立逻辑集群,比如有10G内存,搞5个JVM,每台JVM只分配2G
64位JDK,由于指针膨胀等,比32位消耗更多内存,
要使用64位JDK,管理员能有把握将GC停顿时间控制到最低,低到不会影响用户使用,如何控制大对象,看应用中大对象是否符合“朝生夕死”的原则,而且不能有成批量的大对象产生,保证老年代空间的稳定
一个16G的内存服务器
10G: 5个32位JDK逻辑集群,每一个进程占用2G(堆固定1.5G),占用10G内存
另外建立nginx负载均衡,采用CMS垃圾收集器,标记清除算法是响应时间优先
垃圾回收算法
-
标记清除
每次GC,标记垃圾,然后回收垃圾,优点:简单,缺点:产生碎片
-
复制
内存分成两块,每次只用其中一块,标记垃圾后,将存活的对象复制到另一块,然后把使用过的内存空间一次清理掉
优点:无碎片,缺点:浪费了一半的空间
-
标记整理
先标记垃圾,标记完后,将存活对象向一端移动,移动完了再清理边界以外的对象,优点:无碎片,缺点:效率低
GC
- 默认垃圾回收
java
- 标准 -
- 非标准 -x
- 不稳定 -XX java -XX:PrintFlagsFinal -verison|wc -l
jdk1.8: 年轻代 Parallel Scavenge;年老代:Parallel Old
-
调优先确定哪种垃圾回收器
java -XX:+PrintCommandLineFlags -version
minor gc 年轻代
major gc 老年代
full gc 整个空间gc
组合:Serial+Serial Old ,jdk1.1,1.2 效率低,内存小
- Serial: 单线程(串行),STW,复制---年轻代
- Serial Old:单线程(串行),STW,标记整理或清除---年老代
随着内存越来越大,stw时间会变长
Parallel Scavenge+Parallel Old (JDK8默认)
- Parallel Scavenge: STW,复制,多线程(并行)----年轻代
- Parallel Old:并行GC,标记整理------年老代
多线程,CPU资源浪费在线程切换,内存越来越大时候多线程也没用
ParNew CMS
-
ParNew:STW,复制,多线程,跟PS区别就是跟CMS结合更方便,年轻代
-
CMS(low pause):
- 初始标记,STW,GC roots指向的对象不是垃圾
- 并发标记
- 重新标记,STW
- 并发清除
缺点:碎片化
并发,垃圾回收线程和工作线程同时进行
问题:垃圾清理一个垃圾的时候,这个垃圾有可能又被引用,不是垃圾了 ---- 重新标记纠错(STW)
CMS,毛病多,碎片化严重后将用Serial Old采用单线程标记整理整个老年代
JDK9-G1, CMS毛病多,1.8以上推荐G1
分布式锁,锁续命时期碰上垃圾回收---PS、PO---完蛋,用G1
什么是调优
- 根据要求进行JVM规划和预调优
- 优化JVM运行环境(慢、卡顿)
- 解决JVM运行过程中出现的问题(OOM)
- 案例(吃内存)
- top 观察到内存增长不减,内存泄漏
- 测试环境用图形界面,生产环境--arthas
- arthas不支持jmap, jmap -histo 1196 | head -20 ,把1196线程的对象信息前面20条打印出来,按照对象占用空间大小倒序
线上JVM频繁FULL GC
JVM系统CPU突然飙高
- 业务线程飙高
- 垃圾回收线程飙高
arthas
thread定位线程问题
dashboard观察系统情况
new O(); class对象在method area
method area 1.7: 永久代,1.8:元空间
heap里的class pointer指向method area的instanceClassOop(c++),这个c++对象里有个指针指向heap里的O.class