《架构成长篇三》jvm的深入理解及jvm收集器分析,参数调优

前言

笔者所发的文章都是一些比较系统性的总结,适合有一些开发经验小伙伴,刚入门的小伙伴也可以依次在心里留下一份大致的思想,以后应该也会用得上。

关于jvm,笔者也不是很精通,这里只是做出一些知识经验的总结,希望能有大佬指导或者一起讨论该在什么地方补足自己,感谢感谢。

jvm模型结构

jvm内存主要分为堆,栈,元数据区。元数据区主要存储一些类加载信息(记住存放的是类加载的所有数据即可),常量池,方法信息,jdk1.7及以前是方法区,1.8后用元数据区替换,主要区别是元数据区直接使用内存,方法区还可以限定内存大小;栈数据主要存放线程变量(记住存放的是线程数据即可),栈帧(每个方法的调用会形成一个栈帧压入内存,执行完毕后依次出栈);堆中主要存放运行时创建的数据对象(内存中最重要的一块,也是调优配置最重要的一块),堆中分年轻代(存放新生对象),年老代(存放老年对象),年轻代又分为默认8:1:1的eden:from survivor(后称S0):to survivor(后称S1)。

为什么年轻代中eden:S0:S1是8:1:1呢?首先需要从年轻代中的gc流程说起,年轻代中使用gc复制算法。系统中new出的对象都会放在eden区中,当eden区满以后,会进行MinorGC(又叫YoungGC,后称YGC),将eden中的垃圾对象(没有GCRoots节点)进行回收,回收后幸存对象复制到S0中;当下次eden满时,将S0中的幸存对象复制到S1,当S1满或者对象年龄超过15岁(每次gc对象年龄+1,默认15岁后移入,可配置)对像移入年老代中。首先年轻代的定位就是新对象大,老对象少(都要往年老代里移动),当系统并发请求过来时,每个请求都会创建新的对象,新的对象都会放在eden区中,所以并发量越大,eden区需要的容量就越大。所以eden区应当越大越好,否则提供太多内区区域供复制会造成浪费,其次设计两个Survivor区是为了确保移入年老代中的对象确实是老对象,不会因为S区满直接往年老代移动时所移对象是刚从eden区移动过来的(S0区的作用就是过滤对象,确保移动到年老代中的对象确实是老对象)。

具体结构如下图所示:

年老代和年轻代回收垃圾有不同的垃圾收集器,选择不同的垃圾收集器也是对系统性能提升的重要步骤,下面介绍各类垃圾收集器:

年轻代:

  1. Serial : 单线程收集器,gc时stop the world。
  2. ParNew:并行收集器,多线程版本的Serial收集器。
  3. Parallel scavenge:类似与ParNew,但更关注与系统吞吐量,可以配置吞吐量和gc最大停顿时长,提供自适应配置(系统手机运行状况来自动调节参数来适应最大的吞吐量和停顿时间,新手神器),有时需要根据系统类型(提供用户交互的需要配置停顿时间尽量短,需要保证系统运行效率的则尽量配置高吞吐量)。

年老代:

  1. Serial Old:old区单线程收集器
  2. CMS:并发收集器,使用标记-清除算法,使stop the world的时间缩短(在初始标记,重新标记时仍需停顿),适用与用户交互系统(配合ParNew使用)。
  3. Parallel Old:并行收集器,old版parallel,使用标记-整理算法(配合Paraller scavenge使用)。

常用jvm分析工具

常用的jvm分析工具用 jstack,jmap,jstat,virsualVM,jconsole,MAT等等,下面介绍下个人比较熟悉常用的工具吧。

  • jstat :jstat个人感觉是个比较全面的工具,能够查看jvm中的各类信息。个人比较常用的就是查看gc情况,实时跟踪gc来分析gc运行过程 如 : jstat -gc <pid> 2000 10 (命令的意思是打印堆中的各种信息,包括分代大小,使用量,gc次数,gc耗时等。每隔2000ms打印一次,共打印10次),通过数据的变换可以了解到gc的情况。jstat的其它的参数还有class(显示class信息,数量),compiler(编译数量),gcnew(新区统计),gcold(老区统计),gccapacity(vm内存中使用和占用大小),printcompilation(vm执行信息打印)。
  • jmap:主要使用来获取进程中的对象信息,例如jmap -dump:format=b,file=heap.bin <pid> 打印heap的dump文件, jmap -heap pid查看堆对象信息。
  • jstack:主要用来查看进程中所有线程的信息,是否有死锁。
  • jsoncole:可以连接到本地或远程的进程,查看内部的分区使用情况。
  • virsualVM:可以用来查看进程内存dump的信息,监控线程运行情况等。
  • jvm常用配置参数

  • 内存设置:
  • -Xmn:年轻代大小-Xms:堆初始大小-Xmx:堆最大大小-Xss:栈大小-XX:MinHeapFreeRatio=25:最小扩展堆比例25%-XX:NewRatio=1 :年轻代/年老代=1:1-XX:SurvivorRatio=8 :eden:S0:S1=8:1:1-XX:PretenureSizeThreshold=15 : 设置年轻代15岁入年老代
  • CMS配置
  • -XX:+ UseConcMarkSweepGC : 使用cms收集器-XX:+ UseCMSCompactAtFullCollection: Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长-XX:+CMSFullGCsBeforeCompaction : 设置进行几次Full GC后,进行一次碎片整理-XX:ParallelCMSThreads :设定CMS的线程数量(一般情况约等于可用CPU数量)-XX:+ CMSScavengeBeforeRemark : 设置CMS前进行清理
  • parallel配置:
  • -XX:+ UseParallelGC : 使用parallel收集器 (默认开启UseParallelOldGC)-XX:ParallelGCThreads : parallel收集器的线程数-XX:MaxGCPauseMillis :设置gc停顿时间大小(毫秒)-XX:GCTimeRatio =19: 设置吞吐量大小 公式:1-(1/(1+19))-XX:+UseAdaptiveSizePolicy : parallel自适应模式,新手神器-XX:+ UseParallelOldGC : 使用parallel old收集器
  • 其他收集器
  • -XX:+ UseParNewGC : 使用ParNew收集器-XX:+ UseSerialGC : 使用Serial收集器

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2019年8月1日
    下一篇 2019年8月2日

    相关推荐