JVM基础知识及性能调优2016.06.272JVM基础知识及性能调优JVM基本结构JVM的重要概念及相关参数JVM工具垃圾回收算法、垃圾收集器JVM常见错误及调优示例Java虚拟机的基本结构堆空间直接内存垃圾回收系统执行引擎Java栈本地方法栈PC寄存器JVM堆空间布局JVM的分代年轻代老年代永久代为什么分代不同类型对象的生命周期是不一样的;不同年代的对象采取不同的收集方式,以便提高回收效率;为什么分代如果不分代,每次垃圾回收都需要遍历内存空间,花费时间较长,效率低;如果不分代,多次垃圾回收后,生命周期长的对象仍然存在,效率低;年轻代新生成的对象首先都是分配在年轻代的;年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象;JVM年轻代的结构Eden:Eden用来存放JVM刚分配的对象;Survivor1和Survivro2:两个Survivor空间一样大,当Eden中的对象经过垃圾回收没有被回收掉时,会在两个Survivor之间来回Copy,当满足某个条件,比如Copy次数,就会被Copy到Tenured;年轻代内存的设置两个重要参数:•SurvivorRatio=eden/from=eden/to伊甸园空间和幸存者空间的比值;•NewRatio=tenured/young老年代内存和年轻代内存比值;设置策略:•尽可能将对象预留在新生代;•减少老年代GC次数;•演示NewSizeDemo1;老年代在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到老年代;老年代中存放的都是一些生命周期较长的对象,例如:Session对象、Socket连接等;MaxTenuringThresholdMaxTenuringThreshold是年轻代和老年代的临界值;MaxTenuringThreshold用于控制对象能经历多少次MinorGC才晋升到旧生代;每发生一次MinorGC,年龄就增加1岁,当它的年龄增加到临界值(默认为15岁),就将会被晋升到老年代中;年轻代向老年代的转变年轻代老年代是否达到临界值MinorGCYN,Age+1永久代(持久代)内存永久代内存用于保存类信息。方法区的大小决定了系统可以保存多少个类;如果定义了太多的类,会导致永久代内存溢出,参考代码示例PermTest;在JDK1.8中,废弃永久代,取而代之的是元数据区(Metaspace);直接内存直接内存常用于使用NIO的场景,例如:mina,netty框架;参考DirectBufferOOM、ByteBuffer;直接内存跳过了java堆,使java程序可以直接访问原生内存空间,因此,直接内存访问速度会快于堆内存;直接内存适合申请次数较少,访问较频繁的场合。如果内存空间本身需要平衡申请,则不适合使用直接内存,参考代码示例:AccessDirectBuffer和AccessDirectBuffer2;16JVM基础知识及性能调优JVM基本结构JVM的重要概念、相关参数、日志JVM工具垃圾回收算法、垃圾收集器JVM常见错误及调优示例MinorGC、FullGC新生代GC(MinorGC):指发生在新生代的GC,MinorGC非常频繁,一般回收速度也比较快;老年代GC(FullGC/MajorGC):指发生在老年代的GC,MajorGC的速度一般要比MinorGC慢10倍以上;一般而言,新生代回收的频率高,但是每次回收的耗时都很短,而老年代回收的频率低,但是会消耗更多的时间(演示NewSizeDemo2及visualVM);JVM基本参数参数名称含义默认值-Xms初始堆大小物理内存的1/64(1GB)-Xmx最大堆大小物理内存的1/4(1GB)-Xmn年轻代大小(1.4orlator)-XX:NewSize设置年轻代大小(for1.3/1.4)-XX:MaxNewSize年轻代最大值(for1.3/1.4)-XX:PermSize设置永久代(permgen)初始值物理内存的1/64-XX:MaxPermSize设置永久代最大值物理内存的1/4-Xss每个线程的堆栈大小-XX:NewRatio年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)-XX:SurvivorRatioEden区与Survivor区的大小比值-XX:MaxDirectMemorySize设置最大可用直接内存大小垃圾收集器参数参数名称含义-XX:+UseSerialGC串行垃圾回收器-XX:+UseParallelGC并行垃圾回收器-XX:ParallelGCThreads并行收集器的线程数-XX:+UseParallelOldGC年老代垃圾收集方式为并行收集-XX:+UseConcMarkSweepGC设置年老代为并发收集-XX:+UseParNewGC设置年轻代为并行收集-XX:+UseG1GC使用G1垃圾回收器JVM日志参数参数名称含义-XX:+PrintGC输出GC日志-XX:+PrintGCDetails输出GC的详细日志-XX:+PrintGCTimeStamps输出GC的时间戳(以基准时间的形式)-XX:+PrintGCDateStamps输出GC的时间戳(以日期的形式输出-XX:+PrintHeapAtGC在进行GC的前后打印出堆的信息GC日志•典型的GC日志:•33.125:[GC[DefNew:3324K-152K(3712K),0.0025925secs]3324K-152K(11904K),0.0031680secs]•100.667:[FullGC[Tenured:0K-210K(10240K),0.0149142secs]4603K-210K(19456K),[Perm:2999K-2999K(21248K)],0.0150007secs][Times:user=0.01sys=0.00,real=0.02secs]•最前面的数字“33.125:”和“100.667:”代表了GC发生的时间,这个数字的含义是从Java虚拟机启动以来经过的秒数。GC日志•“[DefNew”、“[Tenured”、“[Perm”表示GC发生的区域,这里显示的区域名称与使用的GC收集器是密切相关的,例如上面样例所使用的Serial收集器中的新生代名为“DefaultNewGeneration”,所以显示的是“[DefNew”。如果是ParNew收集器,新生代名称就会变为“[ParNew”,意为“ParallelNewGeneration”。如果采用ParallelScavenge收集器,那它配套的新生代称为“PSYoungGen”,老年代和永久代同理,名称也是由收集器决定的。接口响应时间过长日志分析-FullGC25JVM基础知识及性能调优JVM基本结构JVM的重要概念、相关参数、日志JVM工具垃圾回收算法、垃圾收集器JVM常见错误及调优示例JVM性能相关分析工具可视化性能监控工具VisualVM内存分析工具MAT图形化虚拟机监控工具JconsoleVisualVM介绍VisualVM官网JavaVisualVM默认没有安装VisualGC插件,需要手动安装,JDK的安装目录的bin目录下双击jvisualvm.exeVisualVM介绍运用VisualVM调优运用VisualVM的快照查看耗时方法的具体时间及调用次数、CPU、内存占用情况,分析问题,解决问题;参考示例:CpuTest和历史邮件;30JVM基础知识及性能调优JVM基本结构JVM的重要概念、相关参数、日志JVM工具垃圾回收算法、垃圾收集器JVM常见错误及调优示例垃圾回收算法复制算法(Copying)标记清除法(Mark-Sweep)标记压缩法(Mark-Compat)分代算法(GenerationalCollection)复制算法(Copying)复制算法把内存分配为两个空间,一个空间(A)用来负责装载正常的对象信息,另外一个内存空间(B)是垃圾回收用的;每次把空间A中存活的对象全部复制到空间B里面,在一次性的把空间A删除;复制算法对内存要求比较大,内存的利用率比较低。适用于短生存期的对象,持续复制长生存期的对象则导致效率降低;复制算法(Copying)标记清除法(Mark-Sweep)标记—清除算法包括两个阶段:“标记”和“清除”。在标记阶段,确定所有要回收的对象,并做标记。清除阶段紧随标记阶段,将标记阶段确定不可用的对象清除;标记—清除算法是基础的收集算法,标记和清除阶段的效率不高,而且清除后回产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间;标记清除法(Mark-Sweep)标记压缩法(Mark-Compat)标记—整理算法是在标记-清除的算法之上进行一下压缩空间,重新移动对象的过程。但是标记—整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存;标记—整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代;标记压缩法(Mark-Compat)内存分代分代算法新生代(复制算法)老年代(标记清除算法、标记压缩算法)垃圾回收算法VS垃圾回收器垃圾回收算法垃圾回收器内存回收算法理论内存回收具体实现垃圾回收器从三个维度理解垃圾回收器回收算法内存年代线程垃圾收集器Serial收集器单线程的收集器;对于单个CPU环境,Serial收集器由于没有线程交互的开销可以获得最高的单线程收集效率;它是虚拟机运行在Client模式下的默认新生代收集器;缺点是因为单线程GC,会造成中断的时间(Sop-the-world)比较大;SerialOld收集器SerialOld是Serial收集器的老年代版本;SerialOld同样是单线程收集器,使用“标记压缩”算法;它是虚拟机运行在Client模式下的默认新生代收集器;Serial/SerialOld收集器运行示意图ParNew收集器ParNew收集器是Serial收集器的多线程版本;ParNew收集器运行示意图:CMS收集器CMS(ConcurrentMarkSweep)收集器是以获得最短响应时间为目标的收集器;CMS过程:初始标记、并发标记、重新标记、并发清除;CMS收集器运行示意图:ParallelScavenge/Old收集器ParallelScavenge用于新生代回收,ParallelOld用于老年代回收,复制算法,并行收集;与ParNew的不同是它的关注点不同,它可以精确的控制吞吐量,例如:JVM共运行了100min。其中垃圾收集花掉1min,那吞吐量就是99%;ParallelScavenge/Old收集器G1收集器G1收集器是一款面向服务端应用的垃圾收集器;并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿时间;分代收集:G1收集器可收集新生代与老年代两种,不需要其他收集器配合就可以独立管理整个GC堆;空间整合:G1采用“标记-整理”算法实现收集器,着意味着G1运作期间不会产生内存空间碎片,收集后可提供规整的可用内存;可预测的停顿:建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集器上的时间不得超过N毫秒;G1收集器JVM参数配置示例(tomcat)JAVA_OPTS='-server-Xms6144m-Xmx6144m-Xmn2048m-XX:PermSize=256m-XX:MaxPermSize=256m-XX:MaxTenuringThreshold=15-XX:GCTimeRatio=19-XX:+DisableExplicitGC-XX:+UseParNewGC-XX:+UseConcMarkSweepGC-XX:+CMSPermGenSweepingEnabled