jvm调优
基于JDK命令行工具的监控
JVM的参数类型:
标准参数:-help、-server 、-client、 -version、-showversion、-cp、classpath
X参数(非标准参数):-Xint:解释执行
-Xcomp:第一次使用就编译本地代码
-Xminxed:混合模式,JVM自己来决定是否编译成本地代码
xx参数(非标准参数):Boolean类型:格式:-XX:[+-] <name>表示启用或禁用name参数
例:-XX:+UseConcMatkSweepGC
-XX:+UseG1GC
非Bollean类型:格式:-XX:<name>=<value>表示name的属性值是value
运行时JVM参数查看
-XX:+PrintFlagsInitial =表示默认值 :=表示JVM修改过的值
-XX:
jps 查看java进程
jinfo 查看运行实参数
jstat查看虚拟机统计信息
类加载信息 -class
垃圾回收信息 -gc
s0c、s1c、s0u、s1u:s0和s1的总量与使用量
ec、eu:Eden区总量与使用量
oc、ou:old区总量与使用量
mc、mu:Metaspace区总量和使用量
ccsc‘ccsu:压缩类空间总量与使用量
ygc、ygct:youngGC的次数与时间
FGC、FGCT:FullGC的次数和时间
GCT:总的GC时间
JVM的内存结构:
JIT编译信息 -compiler
jmap+MAT实战内存溢出
内存溢出自动导出映像文件: -XX:HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
使用jmap命令手动导出:jmap - help 帮助
jmap -dump:format=b,file=heap.hrof
MAT分析:将导出的.hrof文件打开分析各个对象的哥数量和占用的内存
jstack实战系循环与死锁
命令 jstack pid > 文件名
java线程的状态:
NEW:新new一个线程,还没有启动
RUNNABLE:运行状态,并不是就一定执行,可能会等待CPU资源,当获得资源才真正执行
BLOCKED:等待一个锁
WAITING:等待令一个线程来操作
TIMED_WAITING:等待另一个线程来操作
TETMINATED:线程结束
状态转化过程
基于JVisualVM的可视化监控
监控本地Tomcat
监控远程tomcat
监控普通的JAVA进程
基于Btrace的监控调试
Btrace可以动态地向目标应用程序的字节码注入追踪代码
下载Btrace,新建环境变量BTRACE_HOME,添加Path %BTRACE_HOME%\bin
编写脚本:在idea中编写,需要引入jar包 btrace-agent.jar、btrace-boot.jar、btrace-client.jar
1 import com.sun.btrace.annotations.*; 2 import static com.sun.btrace.BTraceUtils.*; 3 import com.sun.btrace.AnyType; 4 import com.sun.btrace.BTraceUtils; 5 6 @BTrace 7 public class TracingScript { 8 @OnMethod( 9 clazz="com.fg.jvmstudy.chapter.MemoryController", 10 method="heap", 11 location=@Location(Kind.ENTRY) 12 ) 13 public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) { 14 BTraceUtils.printArray(args); 15 BTraceUtils.println(pcn+","+pmn); 16 BTraceUtils.println(); 17 } 18 }
命令行执行脚本:btrace <PID> <trace_script>
在jvisualvm中运行
使用详解
拦截方法
拦截的时机:
在入口的地方拦截:默认就是在入口的时候拦截
在返回时拦截:在AnyType前加@return
拦截异常
拦截某一行代码:在Location加入line参数指定需要拦截的行号
拦截this,入参,返回
this:@Self
入参:可以用AnyType,也可以用真实类型,同名的参数用真实类型
返回值:@Return
简单类型:直接获取
复杂类型:反射,类名+属性名,需要指定复杂类型的classpath
注意事项:
默认只能本地运行
生产环境下可以使用,但是被修改的字节码不会被还原
tomcat性能监控与调优
tomcat远程debug
jdwp:定义了调试器和被调试的Java虚拟机之间的通信协议
配置远程tomcat
修改startup.sh
修改catalina.sh
idea:连接远程debug服务并启动
tomcat-managet监控
文档:docs/manager-howto.html
步骤:
conf/tomcat-users.xml添加用户
cof/Catalina/localhost/manager.xml配置允许的远程连接
重启
psi-probe监控
连接步骤与tomcat-manage监控一样
内容:
application:应用的统计信息、请求、session、jsp预编译
data sources
Deployment
Logs
Threads
Clister
System
Connectors
Certificates
Quick check
tomcat调优
内存
线程
maxConnections:最大连接数
acceptCount:线程队列
maxThreads:工作线程数
minSpareThreads:最小空闲的工作线程数
配置
autoDeploy:是否周期性检查是否有新的应用进行部署
enableLookups:在调用request.getRemoteHost()做dns查询,false时直接返回IP
reloadable:是否监控WEB-INF下的class和lib,有变化时自动加载
protocol:连接器
session:可以禁用session
Nginx性能监控与调优
ngx_http_stub_status监控连接信息
需要将此模块编译,默认已编译
添加配置
localhsot = /nginx_status{
stub_status on; 打开stub_status
access_log off; 关闭access_log
allow 127.0.0.1 允许本机
deny all; 拒绝所有
}
cat 文件 打开文件
ngxtop监控信息
安装python-pip
yum install epel-release
yum install python-pip
安装ngxtop
pip install ngxtop
指定配置文件:ngxtop -c 文件路径
查询状态是200:ngxtop -c 文件路径 -i ‘status
查询访问最多IP:ngxtop -c 文件路径 -g remote_addr
nginx-rrd图形化监控
nginx优化
配置线程数和并发连接数
worher_processes 4; 受限于cpu
events{
worker_connections; 每个进程打开的最大连接数,包含了nginx与客户端和nginx与upstream之间的连接,受限与操作系统
multi_accept on; 可以一次建立多少个连接
use epoll;
}
启用长连接
upstream server_pool{
server lcoalhost:8080 weight=1 max_fail=2
.......(多个服务)
keeoalive 300;(三百个长连接)
}
启用缓存压缩
操作系统优化
sysctl.conf文件
JVM层GC调优
JVNM的内存结构
运行时的数据区(规范):
程序计数器 PC Register
JVM支持多线程同时执行,每个线程都有自己的PC Register,线程正在执行的方法叫做当前方法,如果是java代码,PC Register里面存放的就是当前正在执行的指令的地址,如果是C代码,则为空
虚拟机栈JVM Stacks
Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都回船舰一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。
堆Heap
Java堆是Java虚拟机所管理的内存中最大的一块。堆是被所有想成共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆可以处于物理上不连续的内存空间,只要逻辑上市连续的即可。
方法区Method Area
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap,目的是与Java堆区分开来。
常量池Run-Time Constant Pool
运行时常量池时方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息时常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
本地方法栈Native Method Stack
JVM的内存结构:
垃圾回收算法
思想:枚举跟节点,做可达性分析
根节点:类加载器、Thread、虚拟机栈的本地变量表static成员、常量引用、本地方法栈的变量等等
标记清除
算法:
分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有
缺点:
效率不高,标记和清除两个过程效率都不高,产生碎片,碎片太多会导致提前GC
复制
算法:
它将可用内存按容量划分为大小相等的两块,每次只是用其中的一块,当者一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉
优缺点:
实现简单,运行高效,空间利用率低
标记整理
算法
标记过程仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
优缺点
没有了内存碎片,但是整理时耗时
分带垃圾回收
young区用复制算法
Old区用标记清除或者标记整理
对象优先在Eden区分配
大对象直接进入老年代:-XX:PretenureSizeThreshold
长期存活对象进入老年代:
-XX:MaxTenuringThreshold
-XX:+PrintTenuringDistribution
-XX:TargetSurvivorRatio
垃圾收集器
串行收集器Serial:Serial、Serial Old
-XX:+UserSerialGC,-XX:UseSerialOldGC
并行收集器Parallel:Parallel Scavenge、Parall Old,
暂停应用程序,开启多个垃圾收集线程,结束后自动启用应用程序
吞吐量优先
-XX:+UseParallelGC,-XX:+UseParallelOldGC
Server模式下的默认收集器
自适应
-XX:MaxGCPauseMillis=<N> 最大等待时间
-XX:GCTimeRatio=<N> 吞吐量
-Xmx<N> 堆大小
注:不是最优
动态内存调整
-XX:YoungGenerationSizelncrement=<Y> Young区增大默认20%
-XX:TenuredGenerationSizelncrement=<T> Old区增大默认20%
-XX:AdaptiveSizeDecrementScaleFactor=<D> 减小默认4%
并发收集器Concurrent:CMS、G1,停顿时间
响应时间优先
CMS:-XX:+UseConcMarkSweepGC,-XX:+UseParNewGC
过程:
1、CMS initial mark:初始标记Root,STW
2、CMS concurrent mark:并发标记
3、CMS-concurrent-preclean:并发预清理
4、CMS remark:重新标记,STW
5、CMS concurrent sweep:并发清除
6、CMS-concurrent-reset:并发重置
缺点:
CPU敏感、浮动垃圾、空间碎片
CMS的相关参数
-XX:ConcGCThreads:并发的GC线程数
-XX:+UseCMSCompactAtFullCollection:FullGC后做压缩
-XX:+CMSFullGCsBeforeCompaction:多少次FullGC之后做压缩
-XX:CMSSlnitiatingOccupancyFraction:触发FullGC
-XX:+UseCMSInitiatingOccupancyOnly:是否动态调整
-XX:+CMSScavengeBeforeRemark:FullGC之前先做YGC
-XX:+CMSClassUnloadingEnabled:启用回收Perm区
iCMS:适用于单核或双核
G1:-XX:+UseG1GC(jdk7以后)
并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。适合科学计算、后台处理等弱交互场景
并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾收集线程在执行的时候不会停顿用户程序的运行。适合对响应的时间有要求的场景,比如WEB
停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。
-XX:maxGCPauseMillis
吞吐量:花在垃圾收集的时间和花在应用时间的占比。
-XX:GCTimeRatio=<n>,垃圾收集时间占:1/1+n
垃圾收集器搭配
如何选择垃圾收集器
优先调整堆的大小让服务器自己选择
如果内存小于100M,使用串行收集器
如果是单核,并且没有停顿时间的要求,串行或者JVM自行选择
如果允许停顿时间超过1秒,选择并行或者JVM自己选
如果响应时间最重要,并且不能超过1秒,使用并行收集器
可视化GC日志分析工具
Java代码层的调优
jvm字节码指令与javap
i++与++i
i++:先使用再++
++i:先++再使用
字节码:
字符串拼接
String str = "";
for(int=0;i<10;i++){
str = str + "A";
}
字节码
Try-funlly
String str = "a";
try{
return str;
}
finally{
str = "b"
}
String Constant Variable
常用代码优化方法
尽量重用对象,不要循环创建对象,
容器类初始化的时候指定长度
ArrayList随机遍历快,LinkedList添加删除快
集合遍历的时候尽量减少重复计算
使用Entry遍历Map
大数组复制用System.arraycopy
尽量使用基本类型而不是包装类型
不要手动调用System.gc()
及时消除过期对象的引用,防止内存泄漏
尽量使用局部变量,减小变量的作用域
尽量使用非同步的容器
尽量减小同步代码块范围
ThreadLocal缓存线程不安全的对象,SimpleDateFormat
尽量使用延迟加载
尽量减少使用反射,加缓存
尽量使用连接池、线程池、对象池、缓存
及时释放资源
慎用异常,不要用抛异常来表示正常的业务逻辑
String操作尽量少用正则表达式
日志输出注意使用不同的级别
日志中参数拼接使用占位符
附录:
jdk8工具集
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.html
Troubleshooting
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/
jps
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html
jinfo
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html
jstat
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
jmap:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html
mat:
http://www.eclipse.org/mat/downloads.php
jstack:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html
java线程的状态
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr034.html
java线程状态转化:
https://mp.weixin.qq.com/s/GsxeFM7QWuR--Kbpb7At2w
死循环导致CPU负载高
https://blog.csdn.net/goldenfish1919/article/details/8755378
正则表达式导致死循环:
https://blog.csdn.net/goldenfish1919/article/details/49123787
jvisualVM:
https://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/index.html
https://visualvm.github.io/documentation.html
jvisulaVM如何添加插件
https://visualvm.github.io/index.html
btrace下载
https://github.com/btraceio/btrace
https://github.com/btraceio/btrace/releases/tag/v1.3.11
jdwp协议:
https://www.ibm.com/developerworks/cn/java/j-lo-jpda3/
tomcat-manager:
{tomcat}/webapps/docs/manager-howto.html
psi-probe:
https://github.com/psi-probe/psi-probe
tomcat优化相关参数:
${tomcat}/webapps/docs/config/http.html
${tomcat}/webapps/docs/config/host.html
${tomcat}/webapps/docs/config/context.html
${tomcat}/webapps/docs/connectors.html
apr连接器:
http://apr.apache.org/
nginx官网文档
http://nginx.org/en/docs/
nginx安装:
http://nginx.org/en/linux_packages.html
ngx_http_stub_status:
http://nginx.org/en/docs/http/ngx_http_stub_status_module.html
ngxtop:
https://github.com/lebinh/ngxtop
nginx-rdd
http://www.linuxde.net/2012/04/9537.html
jvm的运行时数据区
https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
Metaspace
http://ifeve.com/jvm-troubleshooting-guide-4/
压缩类空间
https://blog.csdn.net/jijijijwwi111/article/details/51564271
CodeCache
https://blog.csdn.net/yandaonan/article/details/50844806
http://engineering.indeedblog.com/blog/2016/09/job-search-web-app-java-8-migration/
GC调优指南:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html
如何选择垃圾收集器
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html
G1最佳实践
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#recommendations
G1 GC的一些关键技术
https://zhuanlan.zhihu.com/p/22591838
CMS日志格式
https://blogs.oracle.com/poonam/understanding-cms-gc-logs
G1日志格式
https://blogs.oracle.com/poonam/understanding-g1-gc-logs
GC日志分析工具
http://gceasy.io/
GCViewer
https://github.com/chewiebug/GCViewer
ZGC:
http://openjdk.java.net/jeps/333
java虚拟机规范
https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
java语言规范
https://docs.oracle.com/javase/specs/jls/se8/html/index.html
javap:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javap.html
字段描述符
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2
方法描述符
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3
字节码指令:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html
常量池:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4
本地变量表:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6.1
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.13
操作数栈:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6.2
Code属性:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3
LineNumberTable:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.12
constant variable:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4
常量表达式
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28
String.intern
https://blog.csdn.net/goldenfish1919/article/details/80410349
String去重
https://blog.csdn.net/goldenfish1919/article/details/20233263