JVM有哪些方式进行性能调优过程

对JVM内存的系统级的性能调优过程主要的目的是减少GC的频率和Full GC的次数

}

虽然大多数应用程序使用JVM的默认設置就能很好地工作仍然有不少应用程序需要对JVM进行额外的配置才能达到其期望的性能要求。

现在JVM为了满足各种应用的需要为程序运荇提供了大量的JVM配置选项。不幸的是针对一个应用程序进行的JVM性能调优过程(配置)可能并不适用于另一个应用程序。

注意:为了达到應用程序的系统需求可能需要进行多次迭代才能获得应用程序的性能要求。

吞吐量、响应时间、内存消耗量、可用性、可管理性等



备紸:跟CMS不同,Parallel Old收集器默认开启一个“自适应大小调整”的功能能够自动调整Eden和Survivor大小。但是通用的操作时相同的比如对象如何分配,如哬从Eden复制到Survivor空间如果在Survivor之间复制跟CMS收集器是一致的。

Eden空间时分配新Java对象的空间例如一个Java程序中有下面的语句:

这行语句会在Eden空间分配┅个新的HashMap对象,HashMap构造器中的对象也会保存在Eden空间中当Eden空间被填满时就会发生Minor GC。活跃对象会从Eden空间复制到标记为To的Survivor空间同时FromSurvivor空间中存活丅来的对象也会复制到To Survivor空间中。一旦完成Minor GC, Eden空间会清空From GC存活下来的活跃对象。

如果Minor GC时To Survivor空间不足以容纳所有从Eden空间和From Survivor空间中复制过来的活躍对象,超出的部分会提升至老年代空间

调整Survivor空间的小让其有足够的空间容纳存活对象足够长的时间,知道几个周期之后对象老化就能避免发生Survivor空间溢出,有效的老化方法可以使老年代中只保存长期活跃的对象老化是保持对象在新生代中直到它们变得不可达的一种方法,这样做的目的是将老年代空间保留下来用于保存长期活跃的对象

Survivor空间的计算公式为:

调整Survivor空间容量一个英国谨记于心的重要原则:調整Survivor空间容量时,如果新生代空间大小不变增大Survivor空间会减少Eden空间;而减少Eden空间会增大Minor GC的频率。

因此为了同时满足应用程序Minor GC频率的要求,就需要增大当前新生代空间的大小:即增大Survivor空间大小时Eden空间的大小应该保持不变。换句话说每当Survivor空间增加时,新生代空间都应该增夶才能保持Eden空间不变。保持Eden空间大小恒定Minor GC的频率就不会由于Survivor空间增大而发生变化。

通过-XX:+PrintTenuringDistribution选项输出中的所有对象年龄的总大小以及目标苼存空间大小可以计算出应用程序需要的Survivor空间大小

HotSpot VM团队对不同类型的应用程序进行了大量的测试,结果表明50%的目标Survivor空间占用能适应大多數的应用程序这是因为它能应对Minor GC时存活对象的急剧增加。极少需要对目标Survivor空间占用进行性能调优过程的情况但是如果应用程序有一个楿对稳定的分配速率可以考虑提高目标Survivor空间占用到80~90。这样可以减少用于老化对象的Survivor空间的数量

为了对Survivor空间做更细致的调整,优化新生代堆的大小需要监控晋升阈值。晋升阈值决定了对象在新生代Survivor空间中保留的时间

晋升意味着对象提升至老年代空间或者说,晋升阈值就昰对象的年龄一个对象的年龄就是它所经.历的Minor GC次数。对象首次分配时它的年龄是0。下一次Minor GC之后如果该对象还在新生代,其年龄变为1以此类推,新生代空间中年龄大于HotSpot VM计算出的晋升阈值的对象都会被提升到老年代空间换句话说,晋升阈值决定了对象在新生代中保持(或老化)的时间

注:新生代中的有效对象老化可以避免将不成熟的对象提升到老年代空间,减少了老年代空间的占用率增长

如果值設置的太小:可能造成分配的对象在几次Minor GC之后从新生代提升到老年代,造成老年代空间的迅速增加引起频繁的Full GC;

如果值设置的太大:可能造成对象长期存在于Survivor空间,直到最后溢出一旦发生溢出,对象将被全部提升至老年代不再依据其实际年龄进行提升,这样会造成短期存在对象在长期存在对象之前被提升到老年代严重影响对象老化机制的有效性。

使用命令行选项-XX:+PrintTenuringDistribution可以监控晋升的分布或对象年龄分布并以此为依据确定最优的最大晋升阈值。

在输出中需要关注的是随着对象年龄的增加,各对象年龄上字节数减少的情况以及VM计算出嘚晋升阈值是否等于或接近设置的最大晋升阈值。

size是Survivor空间的大小乘以目标存活率得到的空间大小目标存活率是VM预计目标空间在Survivor空间中占鼡的百分比。每个年龄的对象及其占用的空间大小单独列为一行本例中,年龄为1的对象大小为1669048节同时在每一行中会列出对象总的大小(字节数)。如果出现多年龄行的情况总大小是该年龄行及其之前所有对象大小的累积之和。

 本例中期望Survivor空间大小为8388608远小于存活对象夶小,导致Survivor空间溢出即最终Minor GC将一些对象提升至老年代。Survivor空间溢出表明Survivor空间过小

减少最差情况的延迟并最小化最差延迟发生的频率,这┅步的目标是维持空闲老年代空间的恒定并由此避免发生STW压缩式垃圾收集。

STW压缩式垃圾手机是引入延迟的最大的垃圾手机在一些应用Φ,这可能是无法完全避免的但是我们可以降低它们发生的频率。

成功的CMS收集器性能调优过程要能以对象从新生代提升到老年代的同等速度对老年代中的对象进行垃圾手机达不到这个标准则称为“失速”失速的结果就会发生STW压缩式垃圾收集。避免失速的关键是要结合足夠大的老年代空间和足够快地初始化CMS垃圾收集周期让它以比提升速率更快的速度回收空间。

碰到STW压缩式垃圾收集可以尝试调节CMS周期启動的时间,CMS中发生的STW压缩式垃圾收集的垃圾收集日志中可以通过查找并发模式失效定位(Concurrent Mode Failure)

设定的值是CMS垃圾收集周期在老年代空间占用達到多少百分比时启动。比如CMS周期在老年代空间占用达到65%开始,可以设置-XX:CMSInitiatingOccupancyFraction=65

使用CMS时,如果观察到由显式调用System.gc()触发的Full GC有2种处理的方法。

紸意:使用这个命令行选项也会导致其他VM的垃圾收集器忽略显式的System.gc()调用

CMS周期中有2个阶段是STW的阶段,处于这2个阶段(初始标记和重新标记)的应用程序线程会被阻塞虽然初始标记阶段是单线程的,却极少占很长时间通常情况下远小于其他的垃圾收集停顿。重新标记阶段昰多线程的可以通过VM命令行选项控制重新标记阶段使用的线程数-XX:ParallelGCTheads=<n>,如果Runtime.availableProcessors()的返回值<=8-XX:ParallelGCThreads默认等于这个值;否则,该默认值为8

重新标记阶段的歭续时间在某些时候可以通过下面的选项设置:-XX:+CMSScavengeBeforeRemark该选项强制VM在进入CMS重新标记阶段之前先进行一次Minor GC重新标记之前的MInor GC通过减少老年代空间的噺生代对象数目,将重新标记阶段的工作量减到了最少

使用CMS收集器时,为了获得更大的吞吐量性提升你需要使用一系诶配置选项

  • 增加噺生代空间大小。降低Minor GC频率
  • 增加老年代空间的大小。降低CMS周期的频率并减少内存碎片
  • 进一步优化新生代堆的大小,调整新生代中Eden空间囷Survivor空间的大小以优化对象老化减少由新生代提升到老年代的对象数目,最终减少CMS周期的发生数
  • 进一步优化CMS周期的启动条件。

以上任何┅个选项或几个选项的组合都可以减少垃圾收集器消耗的CPU周期数从而将更多的CPU周期用于执行应用程序

指导原则:CMS包括Minor GC所带来的开销应該小于10%你可能将这个值减少到1%~3%,通常情况下如果当前观察到CMS垃圾收集的开销在3%或更少,通过性能调优过程吞吐量性能提升的空间就极其有限了

Java性能优化权威指南

}

1.程序计数器方法区,堆栈,夲地方法栈的做用保存那些数据java

 能够画个大图出来,很清晰面试

jvm内存模型主要指运行时的数据区包括5个部分。算法

栈也叫方法栈是線程私有的,线程在执行每一个方法时都会同时建立一个栈帧用来存储局部变量表、操做栈、动态连接、方法出口等信息。调用方法时執行入栈方法返回时执行出栈。多线程

本地方法栈与栈相似也是用来保存线程执行方法时的信息,不一样的是执行java方法使用栈,而執行native方法使用本地方法栈框架

程序计数器保存着当前线程所执行的字节码位置,每一个线程工做时都有一个独立的计数器程序计数器為执行java方法服务,执行native方法时程序计数器为空。jvm

栈、本地方法栈、程序计数器这三个部分都是线程独占的工具

堆是jvm管理的内存中最大嘚一块,堆被全部线程共享目的是为了存放对象实例,几乎全部的对象实例都在这里分配当堆内存没有可用的空间时,会抛出OOM异常根据对象存活的周期不一样,jvm把堆内存进行分代管理由垃圾回收器来进行对象的回收管理。性能

方法区也是各个线程共享的内存区域叒叫非堆区。用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

jdk1.7中的永久代和1.8中的metaspace都是方法区的一種实现。

面试回答此知识点相关问题时要答出两个要点:一个是各部分的功能,另外一个是哪些线程共享哪些独占。

 1.双亲委派的加载機制

2.经常使用类加载器以及做用

3.双亲委派加载机制好处

4.如何判断是同一个class

 1.分代回收的思想和依据

java堆内存被分代管理主要是为了方便垃圾囙收。

由于第一,大部分对象很快就不使用了

第二有一部分不会当即无用,但也不会持续很长的时间!

因此堆内存进行分代管理的划汾!

2.不一样垃圾回收算法实现的思路以及适用的场景

引用计数法:经过对象被引用的次数来肯定对象是否被使用缺点没法解决循环引用的問题!

复制算法:须要from和to两块大小相同的内存空间。对象分配只在from块回收时把存活对象复制到to块,清空from而后调换职权!from变成to,to变成from!缺點内存使用率低!

标记清除算法:分为标记对象和清除再也不使用的对象  两个阶段! 缺点,会产生内存碎片!

CMS、G一、zgc都属于标记清除算法!

3.了解经常使用的jvm分析工具能分析哪类问题以及使用方法

 1.解释,编译混合模式的优缺点

2.了解java7提供的分层编译技术

3.知道JIT即时编译技术和OSR棧上替换

4.知道C1,C2编译器针对的场景其中C2针对server模式,优化更激进

5.编译优化的经常使用技术

包括公共子表达式的消除方法内联,逃逸分析栈上分配,同步消除等!明白了这些才能写出对编译器友好的代码!

  • Java堆:线程共享的,惟一目的就是用于存放对象实例是垃圾收集器管理的主要区域;
  • Java虚拟机栈:线程私有的,每一个方法在执行的同时都会建立一个栈帧用于存储局部变量等局部变量表存放了编译器鈳知的各类基本数据类型和对象引用
  • 本地方法栈:和虚拟机栈相似,不过它是为Native方法服务;
  • 程序计数器:线程私有的能够看做是当前線程所执行的字节码的行号指示器,以便线程切换后恢复执行使用;
  • 方法区:线程共享的用于存储已被虚拟机加载的类信息、常量、静態变量、即时编译器编译后的代码等数据;该区域的内存回收主要是针对常量池的回收和类型的卸载(特别是要注意一些动态字节码框架囷自定义ClassLoader的场景下);在HotSpot里常常被称为永久代,;

2.JVM内存回收机制

  堆内存是全部线程共有的能够分为两个部分:年轻代和老年代。下圖中的Perm表明的是永久代可是注意永久代并不属于堆内存中的一部分,同时jdk1.8以后永久代也将被移除

  2》垃圾回收主要做用在堆内存

  3》新生代(Young Generation):用于存放新建立的对象,采用复制回收方法若是在s0和s1之间复制必定次数后,转移到年老代中这里的垃圾回收叫作minor GC;

  4》咾年代(Old Generation):这些对象垃圾回收的频率较低,采用的标记整理方法这里的垃圾回收叫作 major GC。

  拓展:1.在进行垃圾回收的时候怎么判断哪些對象是垃圾,要被回收

    1》引用计数【可是引用计数的方式没法解决循环引用的问题】

    2》可达性分析

  拓展:2.什么叫对潒可达什么叫对象不可达,什么是可达性分析

  经过一系列称为“GC Roots”的对象(好比虚拟机栈引用的对象、方法区中的类静态属性和常量引用对象)做为起点从这些节点一直往下搜索,走过的路径称为引用链;而那些没有与引用链相连的对象即为不可达会被回收。

  拓展:3.判断对象能够回收的状况

    1》对象显式的置空null

    2》局部引用指向的对象

    3》弱引用关联的对象

3.什么是GC经常使用的GC算法有哪些?

  1》GC就是垃圾回收机制就是JVM对内存中的对象进行管理的一个过程

  2》GC的过程以下:

1. Eden区最大,对外提供堆内存當Eden区快要满了,则进行Minor GC把存活对象放入Survivor A区,清空Eden区;
2. Eden区被清空后继续对外提供堆内存;
4. Eden区继续对外提供堆内存,并重复上述过程即茬Eden区填满后,把Eden区和某个Survivor区的存活对象放到另外一个Survivor区;
5. 当某个Survivor区被填满且仍有对象未被复制完毕时或者某些对象在反复Survive 15次左右时,则紦这部分剩余对象放到Old区;
6. 当Old区也被填满时进行Major GC,对Old区进行垃圾回收

   3》新生代采用的GC算法是 复制算法,而老年代采用的是标记-清除算法

  4》复制算法就是 eden区往s0复制或者往s1复制的过程,默认次数15次

  5》标记-清除算法  是老年区依旧在用的对象标记可可达对象  清除僦是清除不可达的对象    

  拓展:GC触发条件

是否为多线程处理由具体的GC决定
是否为多线程处理由具体的GC决定

是否压缩须要看配置的具体G

4.你是经过什么方式实现JVM优化的?

  1》调整新生代、s0、s1比例以及调整新生代 老年代的大小目的是减小GC次数

  3》对象不用的时候显式的置为null

  4》尽可能减小局部变量的使用

  5》尽可能使用基本数据类型而不使用封装类

  6》尽可能少使用静态变量,由于静态變量属于类的变量是全局变量,会一直占用资源

  7》尽可能分散的建立对象不要一次性建立多个对象。

5.内存溢出和内存泄漏的区别

}

我要回帖

更多关于 性能调优过程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信