基础_JVM调优

1. 总结

(1)jvm包含:类加载器、运行时数据区、执行引擎

(2)运行时数据区包含:方法区、堆、栈、本地栈、pc寄存器

(3)堆包含:新生代youg(Eden, S1, S2)和年老代(Tenured);

(4)方法区:即持久代(Perm)

(5)GC类型:见《深入分析web内幕》8.6.4

(6)判断对象已死的方法:

a.引用计数算法:即给对象添加一个引用计数器,当计数为0时表示不可能被再用;--优点是实现简单,判定效率高;--缺点是无法解决对象相互之间循环引用问题,故主流的JVM没有选用该方法

b.可达性分析算法:即以一些列GC Roots根对象作为起始点,向下搜索,经过的路径称为引用链,当一个对象没有任何引用链相连时表示不可用,即某个对象不可达时表示不可用;JAVA中可作为GC Roots对象包括:栈和本地栈中引用的对象、方法区中静态属性和常量引用的对象;

(7)GC过程:

minorGC: 对E区和S区执行minorGC,存活对象放入S2区,下一次GC前,交换S1和S2;

如果大于则会执行Minor GC,如果Minor GC执行失败则会执行Full GC。

(97)引用类型

强引用:即new,不会被GC回收,除非强引用清空,缺点容易导致内存溢出;

软引用:在内存紧张时才会被回收,适合做缓存;

弱引用:每次GC,都会被回收,不管内存是否紧张,适合做缓存,如WeakHashMap

虚引用:适合跟踪垃圾回收过程;

(98)其他总结:

java方法区存放:静态变量、类信息、常量;

java堆区存放:动态对象;

GC回收的区域包括:方法区、堆、直接内存分配的空间(ByteBuffer.allocateDirect(1024*1024))

(99)JVM与智能卡JCVM区别:

JCVM总体原理:分两部分,卡外JCVM负责编译和转换为CAP,卡内JCVM负责静态调用applet里的install方法进行安装,

并在接受APDU命令是,调用process方法进行处理;

JCVM支持:对象、继承、动态对象创建、虚拟方法、接口和异常;

JCVM不支持:线程、GC、动态类加载、synchronized、double\float等;

ClassLoader是用来动态的加载class文件到虚拟机中;

2. jvm调优总结:

(1)堆总大小:最大为物理内存的80%,默认值为物理内存的 1/4;

-Xms:初始堆大小,堆包含新生代和老年代;如果不设置默认为1/64物理内存大小,即16G为256m;

-Xmx:最大堆空间,建议与Xms设成一样的值,最大值设置为可用内存的最大值的80%避免 JVM 反复重新申请内存,导致性能大起大落,默认值为物理内存的 1/4;

(2)新生代:建议为堆的1/4(最大1/3)且E区建议为新生代的3/4,S区共1/4,Hotspot默认E区和S区比例为:8比1,即两个S为4比1

(3)年老代:建议为堆的3/4

---XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力。

---仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。

---客户端,应该响应时间优先;后端服务程序,吞吐量优先;

(4)栈:

-Xss:线程栈大小,JDK 5.0 以后每个线程堆栈大小为 1M,以前每个线程堆栈大小为 256K,可设置为512K

(5)方法区:即持久代,根据应用程序war包大小设计即可

(6)GC类型选择:分为4种,串行、并行、CMS收集器和G1

串行GC: 单线程进行GC,执行时会停止业务线程,CPU利用率最高,停顿时间即用户等待时间比较长

-XX:+UseSerialGC:年轻代SerialGC,年老代Serial Old

总结:年轻代用复制算法,年老代用标记整理算法

并行GC:多线程独占式进行GC,执行时也会停止业务线程,吞吐量相比CMS高;----- 吞吐量优先

-XX:+UseParNewGC:年轻代ParNewGC,年老代Serial Old,可指定年老代用CMS GC --- 常用

-XX:+UseParallelGC:年轻代ParallelScavengeGC,年老代Serial Old

-XX:+UseParallelOldGC:Parallel收集器+ 老年代并行

总结:年轻代用复制算法,年老代用标记整理算法

并发GC(CMS):多线程非独占式GC(即同业务线程并行执行),停顿时间少,但年老代用的标记-清除算法,所以吞吐量小点;-- 响应时间优先

-XX:+UseConcMarkSweepGC:年轻代ParNewGC,年老代CMS

总结:年轻代用复制算法,年老代用CMS算法,即升级版的标记-清除算法,缺点:容易产生大量空间碎片

G1:并行GC和并发GC的结合,支持很大的堆,高吞吐量和低响应时间 --支持多CPU和垃圾回收线程

1. 在主线程暂停的情况下,使用并行收集,在主线程运行的情况下,使用并发收集;

2. 可预测停顿,这是G1的另一大优势,降低停顿时间是G1和CMS的共同关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。

3.内部机制不同:上面提到的垃圾收集器,收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆的内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔阂了,它们都是一部分(可以不连续)Region的集合。

4. 与GMS的区别:空间整合,G1收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次GC。

总结:串行GC和并行GC用于新生代,串行GC和并发GC用于年老代;

详见:https://blog.csdn.net/u013812939/article/details/48782343 ---- Serial,Parallel,CMS,G1四大GC收集器特点小结

(7)垃圾回收算法:标记 -清除算法,复制算法,标记-整理算法,分代收集算法

标记 -清除算法:缺点是容易产生内存碎片,标记和清除效率不高

复制算法:优点是不会产生内存碎片,适用于生命周期短的情景,即新生代,缺点是:对象存活率高时较多复制操作效率低+50%空间浪费;

标记-整理算法:好

分代收集算法:新生代采用复制算法,年老代采用标记-整理算法和标记-清除算法;

详见:http://www.importnew.com/23752.html --- 好!!!

3. 相关命令

(1) jps -v : 查看jvm的启动参数;

jinfo pid: 查看和修改java的环境变量和JVM运行参数;

(2) jstack pid : 打印栈信息,可用于查看程序如何崩溃和何处发生问题的;

(3) jmap -heap pid: 查看堆信息,包括堆概要、E/S1/S2、老生代等各区大小和使用率,GC的类型等,不显示GC时间和次数;

-histo:live pid: 按照占用空间大小打印程序中类的信息;

pid : 按照占用空间大小打印程序中加载的动态链接库的列表;

-dump:[live,]format=b,file=xxx pid 使用hprof二进制形式,输出jvm的heap内容到文件=xxx

(4) jstat -gc pid interval: 查看jvm的堆中的新生代、年老代、持久代、GC等使用情况、GC时间和次数;

也windows下的jvm调优工具可用jdk自带的VisualVM或Jconsole;在linux下面也可以使用如上工具,在windows下远程连接LInux服务器进行性能分析,也可用ps -ef | grep java, 可查看tomcat进程启动的Jvm参数;或在tomcat/bin/catalina.sh里配置JAVA_OPTS变量值;

(5) VisualVM、JMAT、 Jconsole(已过时)、JProfiler(商业化的分析定位工具)

https://blog.csdn.net/keketrtr/article/details/53516011 ---- visualVM远程连接Linux服务器进行JVM监控

(6)总结: jvm相关的各种命令:《分布式服务架构--李彦鹏》6.6 ---- 好!!! 和 《Java程序性能调优》6.3 ---- 好!!!

详见:https://blog.csdn.net/tzs_1041218129/article/details/61630981 ---JVM性能调优监控工具jps、jstack、jmap、jhat、jstat等使用详解---好!!!

4. OOM内存溢出处理和解决:

(1). 具体流程可见:《分布式服务架构--李彦鹏》6.6

(2). 异常信息:Tomcat 运行过程遇到Caused by: java.lang.OutOfMemoryError: PermGen space, 或者java.lang.OutOfMemoryError: Java heap space错误。

(3). 出现情况:

(1)堆空间不足:JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。

(2)方法区不足:如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误,常出现在web服务器中,jsp被动态编译成java servlet类,加载到方法区,因此JSP多的web工程可能会产生这个异常;

(3)不能创建本地线程:超过最大线程数限制;

(4). 调试过程为:

(1) 用jmap dump堆详细信息;

(2) 将dump文件导入MAT/jhat/visual VM等图形工具,图形查看内存泄露报表,自动检查可能存在内存泄露的对象,通过报表展示存活的对象以及为什么他们没有被垃圾收集;

参见:https://mp.weixin.qq.com/s/Xb1im4jG_Cobhas4q4YT1Q 线上服务CPU100%问题快速定位实战 --- 好 !!

https://mp.weixin.qq.com/s/iOC1fiKDItn3QY5abWIelg 线上服务内存OOM问题定位三板斧 --- 好!!

详见: http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)--- MAT(Memory Analyzer Tool)工具入门介绍

详见: https://www.cnblogs.com/101key/p/6876777.html ---- JVM内存溢出解决案例

参见:https://www.cnblogs.com/ThinkVenus/p/6805495.html --- 什么是java OOM?如何分析及解决oom问题?

(5). 溢出案例和解决:

(1) zxb: 集中客服系统->方法区只有128M -> 随着客服系统功能越来越多,war包增大+大量的JSP被动态编译成java servlet类,加载到方法区,导致方法区溢出OOM;

(2)由于使用了HibernateORM框架,且开启了其二级缓存,使用了EHcache,但在EHcache中没有控制缓存对象个数,缓存对象增多,导致内存紧张,导致频繁GC,甚至OOM:GC overhead limit exceed

(3) 线程数太多:由于Log4j阻塞导致启用大量线程,超过了最大线程数量------详见《分布式服务架构--李彦鹏》6.8.1

4. Full GC分析和问题解决:

(1)触发条件大致情况有以下几种情况:

程序执行了System.gc() //建议jvm执行fullgc,并不一定会执行

执行了jmap -histo:live pid命令 //这个会立即触发fullgc

在执行minor gc的时候进行的一系列检查

使用了大对象 //大对象会直接进入老年代

在程序中长期持有了对象的引用(通常为无效引用导致的内存泄露)//对象年龄达到指定阈值也会进入老年代

jvm参数Xms与Xmx保持一致,避免因所使用的Java堆内存不够导致频繁full gc以及full gc中因动态调节Java堆大小而耗费延长其周期;

(2)进入老年代条件:

---达到一定年龄晋升:JVM给每个对象定义一个对象年龄计数器,每minorGC一次,将移动到s空间,年龄加1,当年龄增加到一定程度(默认是15岁),就会晋升到老年代;---S区中相同年龄对象总和大于S区一半,则大于等于该年龄对象直接进入老年代;---minorGC时,S区空间不够存放大对象,将会直接进入老年代;

(2)线上排查问题步骤:

a. 用jmap -heap pid看一下JVM各分区总体占用情况,然后用jmap -histo:live pid初步分析内存映射,初步分析各对象的占比情况,如无法定位到关键信息,则利用jmap -dump生成离线文件做进一步分析;

b. 拿到dump文件后,使用Java heap分析工具(如VisualVM、MAT等),找出内存占用超出预期的嫌疑对象;

c. 分析嫌疑对象和其他对象的引用关系;

d. 分析程序的源代码,找出嫌疑对象数量过多的原因;

总结:内存泄漏的原因分析,总结出来只有一条:存在无效的引用!如使用线程不安全的list、hashmap等导致无法GC;如定时任务定时调用,每次调用生成10个线程处理,而它又使用了非线程安全的List对象,导致List对象无法被GC收集,所以这里将List替换为CopyOnWriteArrayList 。

详见:https://blog.csdn.net/alli0968/article/details/52460008 使用jmap和MAT分析JVM堆内存 -- 好!!!

https://blog.csdn.net/wilsonpeng3/article/details/70064336 -- 线上full GC排查

https://blog.csdn.net/n8765/article/details/50911742 系统频繁Full gc问题分析及解决办法

5. jvm调优案例:

(1) 好的运行情况(手机保障订单系统-生产服务器):YGC次数少,无FGC

[app@qycp-ord01 ~]$ jstat -gc 45349 3000

S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT

4096.0 4096.0 2560.0 0.0 1040384.0 364351.6 11534336.0 84792.2 262144.0 50480.9 764 19.221 0 0.000 19.221

4096.0 4096.0 2560.0 0.0 1040384.0 364351.6 11534336.0 84792.2 262144.0 50480.9 764 19.221 0 0.000 19.221

(2) 坏的运行情况(手机保障订单系统-测试服务器):YGC和FGC次数和时间都很大

[app@qycp-bak01 ~]$ jstat -gc 27464 3000

S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT

1024.0 1024.0 0.0 704.1 1536.0 444.3 49664.0 39292.4 48640.0 48534.6 334033 1038.212 14176 909.836 1948.048

1024.0 1024.0 0.0 704.1 1536.0 795.7 49664.0 39292.4 48640.0 48534.6 334033 1038.212 14176 909.836 1948.048

(3) 手机保障订单系统参数:

16G内存:堆区(包含新生代和年到代)设置为内存的80%即12G,持久代超过war包大小即可,可设为256m

新生代:1G,具体Eden占98%, S1=S2=4m

年老代:11G

持久代:-XX:PermSize=256m -XX:MaxPermSize=1024m

例:订单jvm系统设置-server -Xms12288m -Xmx12288m -XX:MaxNewSize=1024m

-XX:PermSize=256m -XX:MaxPermSize=1024m

详见上面生产服务器运行情况;

(4) H码系统JVM调优案例:8G内存,8核,64位 ---好!!!

调优原因:redis+集群方案,8G内存偏小

调优目标:后端服务程序,故减小GC时间,提高吞吐量

调优总体方法:增大堆空间,减小方法区和栈空间,堆里增大E区,用并行GC

方法区:即持久代,由于H码查询程序不大,设为128m,最大256m

堆区:系统默认为1/4,即2G,故调优初始堆和最大堆设为一样,减少jvm反复重新申请内存带来的性能波动;

可用内存的80%,即堆总体为6G,

新生代大点,设为1/3,即2G,减少GC时间,提高吞吐量;

老生代设为2/3,即4G;

栈区:系统默认为1M,改为512k,减少占用堆的空间,且使剩余内存支持更多的线程;

GC类型:新生代和老生代都使用并行GC,提高吞吐量;

最终效果:GC时间减小,JVM各项指标运行正常;

---单个机器的极限并发量一般为2000-5000/秒;

(5) 吞吐量优先案例:《Java程序性能调优》5.4.5 ---- 好!!!

在4G,32核CPU的计算机上,进行吞吐量优先优化,尽量减少系统执行垃圾回收的总时间:

===========================参考网址===================================

1. jvm总体架构:---好

http://blog.csdn.net/stanlee_0/article/details/51171382

2. jvm调优总体策略:---好

http://mp.weixin.qq.com/s?__biz=MzAwNTQ4MTQ4NQ==&mid=2453559992&idx=1&sn=08a48401f425f434bd12c7bb4f0ac0ce&chksm=8cd10fdabba686cca7ba03055efdb9697a1252e8c74d4d9a09bc2a1176955ac798c8f0ec6017&mpshare=1&scene=23&srcid=0913AVJjx5XkU974G57sjcUU#rd

注:浅谈对JIT编译器的理解http://www.cnblogs.com/insistence/p/5901457.html

3. Tomcat 调优及 JVM 参数优化:包含jvm调优参数介绍、推荐的配置等 ---好

https://blog.csdn.net/ldx891113/article/details/51735171

4. 其他

JVM调优总结(这个总结得比较全面)---------好!!!

https://blog.csdn.net/wuzhilon88/article/details/49201891

Linux使用jstat命令查看jvm的GC情况---------好!!!

https://www.cnblogs.com/qmfsun/p/5601734.html

jvm系列(七):jvm调优-工具篇 --- 好!!!!

https://www.cnblogs.com/ityouknow/p/6437037.html

http://www.importnew.com/19275.html --- 工具调优步骤

SSH登陆远程Linux服务器运行VisualVM, 进行Java性能分析

https://blog.csdn.net/jeff_fangji/article/details/40070785

学习JCVM之二JCVM的工作原理 -智能卡JCVM---好!!!

https://blog.csdn.net/q2360c/article/details/327405

https://blog.csdn.net/supergame111/article/details/25353979

猜你喜欢

转载自blog.csdn.net/zxb448126/article/details/81208513