查看jvm运行时参数

PrintFlagsFinal

java -XX:+PrintFlagsFinal -version
查看虚拟机默认参数

jps

专门查看java进程的
jps
jps -l查看完全参数

jinfo

jinfo是查看运行时进程的详细信息。比如
jinfo -flag MaxHeapSize 11956
查看这个java进程的最大堆大小
jinfo -flag UseG1GC 11956
查看是否使用了G1垃圾回收器
输出是XX:-UseG1GC,其中-表示没有使用

jstat

jstat查看jvm的统计信息
类加载,垃圾回收信息,jit编译信息

jstat -class 11956
Loaded  Bytes  Unloaded  Bytes     Time
28968 58273.9      301   462.6      39.13


jstat -gc 11956
S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  1024.0  0.0    0.0   145920.0  2871.8   453120.0   246336.3  193100.0 179678.6 26240.0 21961.4   1578   12.603 1484   410.614  423.217

S0C,S0U,S1U,S0U,s0,s1区的使用量和总量
EC,EU:Eden区的总量和使用
OC,OU,Old区的总量和使用
MC,MU,Metaspace区总量和使用,其中这个metaspace是存放Class对象的。
CCSC,CCSU,压缩类空间总量和使用。
YGC,YGCT,YoungGC的次数和时间
FGC,FGCT:FullGC的次数和时间
GCT,总GC的时间。

ps 通过官网 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html#BEHHGFAE来查询

如何导出内存镜像文件

1,内存溢出是自动导出,加上2个参数
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
2,Jmap导出
jmap -dump:format=b,file=heap.hprof 11956
导出的文件用mat打开,可以查看到对象的数量和大小。可以分析内存溢出的问题。

jstack

打印jvm里面所有的线程,看看cpu暴增的原因之类的。java线程的状态有new,runnable,blocked,waiting,timed_waiting,terminated,
cpu飙高,可能是死循环。或者死锁。cpu过大可能导致新的请求无法处理。
方案:
1,查看cpu那个进程高。ps auxw | head -1;ps auxw |sort -rn -k3 |head -11
2,打印jstack 11569 ->11.txt.
3,top -p 7792 -H,打印所有的线程。找出高的线程,然后将其从10进制转换为16进制,得到一个id
4,在打印的文件里面找到这个id对应的线程,然后分析。具体代码。

deadlock。

JVisuaIVM

可视化监控工具,可以监控远程和本地。
里面有很多功能,和jstack,jmap类似,几乎包含了上面所有的命令以及mat,里面有个抽样的功能,

其中cpu抽样,可以看到哪个方法的执行时间。从而针对性的优化代码

内存抽样,可以看到每个类占用的内存实例数等信息。可以看到那些对象可能导致内存泄漏。

Btrace

在程序不重启,正在运行的时候修改动态的修改字节码。
下载btrace,然后加入到环境变量,写好脚本,然后执行 btrace pid 脚本,执行完,字节码就加入到运行的环境里面了。只要是java代码都可以拦截。

参数,返回值,异常都可以获取到,还可以判断某一行代码是否执行

注意点:1.只能本地执行。不能远程使用。
2.修改了字节码,退出时不会回复

tomcat

1,tomcat远程debug
基于JDWP协议,定义了调试器和java虚拟机之间的协议。
主要是修改服务器上tomcat的配置,然后调试。如果是个普通的java进程需要修改这个java进程的启动脚本,加上一些配置。

2.tomcat-manager
tomcat自带的,还是修改tomact配置,增加用户,增加配置。可以查看tomcat很多信息,比如有哪些应用。且对其进行处理。查看线程信息之类的。以及线程处理时间之类的。

3.psi-probe
先下载probe这个项目源码,然后打包,将其war包放入到tomcat的webapp下面,即可,启动tomcat即可。tomcat的配置和上面一样。

4,tomcat优化
1,内存优化
2,线程优化
主要需要配置maxConnections最大连接数。acceptCount:连接满了之后的新的连接进入队列,超出队列,则拒绝请求。maxThread:工作线程数,和cpu相关…
3.配置优化
autoDeploy,周期性检查是否有新的应用加了进来,但是会浪费一个线程资源。默认为true,建议为false.
enableLookups:开启后会对请求做一个dns查询,浪费性能。
reloadable:监控web-inf/classes和web-inf/lib目录,浪费性能。默认没有开启。
还有设置协议为nio,
还可以禁用session,存到redis里面。

nginx

可以通过ngxtop,动态查看访问最多的ip,访问最多的返回码等信息。
Mginx-rrd是个图形化工具,这个工具统计的信息可能滞后,因为它是通过定时器来统计的。
优化:
增加工作线程,增加并发连接数,默认是一个工作线程,1024个连接。
一般多少个cpu,就多少个工作线程,启用epoll网络模型。
启用长连接。浏览器和nginx之间是有长连接的,但是Nginx和后端服务之间是没有长连接的,需要配置。
启用缓存,压缩。
操作系统优化。

jvm调优

运行时数据区(这是一个规范)

jvm内存结构
程序计数器:这个就是线程私有的,存放的是线程正在执行指令的地址。
java虚拟机栈:线程私有的,生命周期和线程一样,里面的元素是栈帧,每一个栈帧的入栈到出栈意味着一个方法的执行调用和结束。栈帧存放的是方法的局部变量表,返回值信息,方法出口灯
java堆,分为新生代,老年代,线程共享的,每一个实例都是在堆里面分配内存的。
java方法区,线程公有的,存放,常量。被虚拟机加载的类信息,编译器编译后的代码。(运行时常量池:各种常量信息,在类加载后放进去存放。)

上面的是java虚拟机规范的jvm内存结构

下面是实际的jvm内存结构(实现)

堆:和上面的一样

非堆区(metaspace)

存放字节码文件,class,package,method,常量池,符号引用。

ccs:压缩类空间,只有你启用了这个才会存在(java堆中每个对象都有一个指针指向自己的Class,因为在64位虚拟机下面,每个指针64位长度,为了压缩,采用32位,那么数据就会存到ccs里面)

codeCache:jit即时编译的代码,jvm执行的本地代码。如果没有采用jit,没有使用native方法,那么就是空的。

ps:java本地代码,就是采用编译方式启动java进程,然后代码会被jit编译为机器码,放入到metaspace里面

判断对象是否回收的算法
可达性分析算法,从根节点到这个对象是否可达。
根节点很多:类加载器,Thread,虚拟机栈的本地变量表,常量应用,垃圾回收的时候,通过这些根节点来进行可达性分析。

垃圾回收算法
标记-清除:做可达性分析之后,标记所有可回收的对象,标记完成后统一回收。缺点效率不高,产生大量内存碎片。
复制算法,吧内存划分为大小一样的2块,每次使用其中一块,当其中一块无法分配内存后,进行垃圾回收,吧可达的对象复制到另外一块上,再把这块用的空间一次性清除。
优点,简单高效
缺点,内存利用不高
标记-整理。先判断哪些对象是可达的,然后统一向一端移动,然后清除掉边界外单位内存
相对于标记清除,少了内存碎片,但是更加耗时。

一般来说,yong区使用复制算法,old区采用标记清除或者标记整理算法。

对象分配:
对象优先分配到Eden区,大对象直接到老年代,存活时间长的对象进入老年代。

垃圾回收器
串行收集器Serial:Serial,Serial Old,单线程的垃圾回收器。当内存不够时,虚拟机会启动一个单线程的垃圾回收器。
并行收集器Parallel: Prallel Scavenge,Parallel Old,吞吐量优先
并行:指多条垃圾回收线程并行工作,用户线程仍然处于等待状态。适合科学计算,后台处理等弱交互场景,

并发收集器Concurrent:CMS,G1,停顿时间短优先。

并发:指多条垃圾回收线程和用户线程并行,也许是交替进行,垃圾回收的时候不会停止用户程序的运行,适合web,对相应时间有要求的应用

停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。XX:MaxGCPauseMillis

吞吐量:花在垃圾回收的时间和花在应用时间的占比-XXGCRimeRatio=,垃圾收集时间栈:1/1+n

-XX:+UseSerialGX -XX:+UseSerialOldGC
使用串行,一般不使用

-XX:+UseParallelGC,-XX:+UseParallelGC
使用并行,吞吐量优先
Server模式下默认收集器。cms是old区的,

并发
CMS:XX:+UseConcMarkSweepGC -XX:+UseParNewGC
G1:-XX+UseG1GC

由于虚拟机采用分带算法
new old
Serial SerialOld
parNew SerialOld
ParaLLelScavenge SerialOld
Serial CMS
ParNew CMS
G1 G1

其中CMS可能退化为SerialOld,在担保分配空间失败后

如何选择垃圾回收器

1.调整堆的大小让服务器自己选择
2.如果内存小于100,串行
3,如果单核,且没有停顿时间的要求,串行或者jvm自己选。
4,如果允许停止时间超过一秒,选择并行或者jvm自己选。
5,响应时间很重要,不能超过一秒,使用并发垃圾回收器。

使用并行垃圾回收器,
-XX:+UseParallelGC手动开启
-XX:ParallelGCThread=,多少个GC线程。
cpu>=8 N=5
Cpu<8 N=CPU

并行垃圾回收器有个自适应的特性。内存不够了会自动变大。
因此一般不使用。

CMS并发
低停顿,低延迟
老年代

收集过程。
1,初始标记,标记GCroot,这个过程需要停止应用程序。
2,并发标记。
3,并发预处理
4,重新标记,也是需要停止应用的,
5,并发清除
6,并发重置

缺点,cpu敏感,浮动垃圾,空间碎片。标记清除算法。

CMS参数优化
-XX:ConcGCThreads,并发的GC线程数
-XX:+UseCMSCompactAtFullCollection:fullGC之后会做压缩,减少内存碎片。
可视化GC日志分析工具
-XX:CMSFullGCsBeforCompaction:多少次FullGC之后压缩一次。
-XX:CMSInitiatingOccupancyFraction:触发FullGC,老年代空间使用了多少比例后会触发这个fullGC,92%
-XX:+CMSScavengeBeforRemark:fullGC之前先做YGC。

G1垃圾回收器
大内存,小停顿,同时是新生代和老年代。
G1里面没有物理意义的新生代和老年代,他是一个个的region,多个region构成了逻辑上的新生代和老年代。
StaB,GC开始的时候存活对象的快照。
RSet:记录了其他region里面引用了本region对象的关系。
G1 YoungGC
新生代进入Eden区
存活对象进入su区
存活时间长的对象进入Old区。
和其他一样

没有fuLLGC 只有MixedGC
回收Young区和部分Old区。不是回收全部的old区。

global concurent marking(全局标记)
1,标记GC root,stw
2,标记存活Region
3.标记存活对象。
4.重新标记,stw
5.部分stw

根据参数来设定,InitiatingHeapOccupancyPercent,默认45%,就会触发global concurent marking

G1HeapWastePercent默认5%。
再global concurent marking之后,我们可以判断有多少对象需要回收,也就是说要判断要回收的对象是否超过了5%,如果超过了就要回收。在每次YGC之后和Mixed GC之前,会检查参数是否达到了这个值,如果达到了就会MixedGC

是否需要切换到G1
1.50%堆被存活对象占用
2,对象分配速度快
3,垃圾回收时间长

GC日志简析
1吞吐量(应用线程时间和总时间的比例)和停顿时间

通过工具分析
1.在线 gceasy.io
2.GCViewer

具体的分析都可以在orcal官网查看
首先要打印gc日志,输入一些参数,会让gc的时候把文件打印出来。在线工具更加方便

ParallelGC调优原则
1.不要设置最大对内存
2.优先设置吞吐量目标
3.吞吐量达不到要求,调大最大内存,不要让os使用swap,如果还达不到降低吞吐量。
4.吞吐量能达到,GC时间长,设置停顿时间目标

就是不断尝试。分析gc次数。

G1最佳实践
1.年轻代:避免使用-XMn,-XX:NewRatio,等显示设置young区大小,会覆盖暂停时间目标。
2.暂停时间目标:不要太苛刻,其吞吐量目标是90%的应用时间和10%的垃圾回收时间,太严格影响吞吐量。
3.MixGC

分析gC的原因。

字节码

1,先编译一个java文件,生成class文件
2,找到其所在的目录
3,执行 javap -verbose aaa.class->test1.txt

intern区别

1.6 常量池没有,加进去,有,不管
1.7 常量池没有,加个指向堆对象的引用。