JAVA虚拟机性能参数调优指导书.doc_第1页
JAVA虚拟机性能参数调优指导书.doc_第2页
JAVA虚拟机性能参数调优指导书.doc_第3页
JAVA虚拟机性能参数调优指导书.doc_第4页
JAVA虚拟机性能参数调优指导书.doc_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java虚拟机性能参数调优指导书(仅供内部使用)目 录1概述62JAVA虚拟机运行机制概览62.1运行时分析62.2垃圾收集和线程同步83JAVA虚拟机参数分类说明93.1Java虚拟机标准参数93.2Java虚拟机扩展参数114JAVA应用性能测试调优经验总结144.1GC调优参数的使用144.2JIT调优参数的使用154.3Java线程调优参数的使用155结束语166参考文献16表目录表1 JVM 标准参数集11表2 JVM 扩展参数集11表3 JVM GC/Hotspot相关参数集13表4 JVM 性能统计参数集14Error! Reference source not found.关键词:Java、垃圾收集、虚拟机、即时编译摘 要:随着JAVA在应用系统级的项目开发中的使用越来越广泛,虚拟机、垃圾收集、热点编译、J2EE等新技术层出不穷,JAVA作为系统级开发的一个选择的优势也越来越明显,在此同时其不能完全编译、垃圾收集等与生俱有的特征也使得JAVA备受争议的“慢”得到更多的关注。本文通过对JAVA虚拟机的运行机理的分析,以及JAVA虚拟机参数使用说明等描述,试图使读者能够更好的运行他的基于JAVA的应用系统,以最小的代价换取最大的收益。缩略语清单:缩略语英文全名中文解释JAVASUN公司发明的一种语言JVMJava Virtual MachineJAVA虚拟机GCGarbage Collection垃圾收集HotSpotJava虚拟机内部的一种热点编译技术JITJust-In-Time即时编译技术1 概述Java在大行其道的同时也在为自己与生俱来的缺陷不断的努力着,我们有理由相信Java的开发设计者们真是一群天才。构成Java技术的基石就是JVM的虚拟机技术,这时的Java已经不再是一门简单的语言,而是语言、开发包JDK与虚拟机的完美结合,而这里面的虚拟机则是融合了编译技术、CPU技术的Java存在的基础所在。既然那么多的优秀的人为提升虚拟机性能做了那么多的工作,我们有什么理由不去充分利用这些宝贵的资源呢?本文就是试图从原理分析到参数应用上来帮助读者更大的发挥Java虚拟机的性能极限,使这样一个优秀的产品更好地为我们服务。2 JAVA虚拟机运行机制概览2.1 运行时分析首先让我们来看看所谓的Java虚拟机在运行起来后是什么样子的,从外面来看一个Java虚拟机的运行实例就是一个运行着的Java进程,Java进程在启动过程中做了如下工作,一、根据环境变量的设置或者Java进程的命令行参数将Java Class字节码加载到内存中,这样的Java字节码是Java虚拟机所能够识别的虚拟机指令的集合,Java虚拟机在解释执行字节指令的同时,根据某些代码的使用频率,将其中一部分字节码翻译成机器能够识别的二进制指令保存在内存中,在以后对这部分代码的调用,则由Java虚拟机的代码控制CPU直接执行内存中的这部分二进制指令,这个就是Java虚拟机的热点编译技术。而在早期的Java虚拟机实现中是采用全部字节程序解释执行的方式,后来发展了Java静态编译技术,这种技术是在Java程序编译成字节码后,由一个本地编译器将这些字节码编译成二进制可执行文件,这种编译技术不利于程序的移植。再后来发展的Java的动态编译技术,这时的编译过程是在Java装载字节码文件时进行的,而此时的问题是Java在启动时需要花费很长的时间来编译这些字节码。直到最后流行的Hotspot技术的出现,此时编译仅仅运行于少部分代码。按照80/20的原则,程序的百分之80的时间仅仅运行其百分之20的代码,这样一个能够平衡启动时间、移植性的中间方法解决了人们的大部分问题。之后,让我们看看Java虚拟机的内部体系结构,从下面的体系机构图来看,Java的Class字节码文件经由类加载子系统加载到内存中时,虚拟机根据文件内容将类的方法和数据加载到称为方法区的地方,堆是用来为运行时类实例提供存放场所的地方,这样的堆也称之为对象堆空间。而Java栈和PC计数器则是为了Java线程而设计的,每一个Java线程一旦创建,它都将得到一个属于他自己的PC计数器(程序计数器指针,类似于CPU中的IP指令指针计数器)以及一个线程栈,在新版本Java Hotspot VM中是没有本地方法栈和线程栈之分的,只有一个线程栈的模块。这样每个线程的运行都是在属于自己栈空间内的,而所有的线程则共享着一个堆空间。当然在线程实现上不同的Java虚拟机的内部实现可能各有不同,有的自是直接将Java线程和操作系统内核线程绑定起来的,在虚拟机进程内部创建一个Java线程虚拟机就会请求操作系统为该一个进程创建一个内核线程,将线程之间的调度交给了操作系统内核来完成。而在早期的Java虚拟机一些实现中,Java线程对于操作系统来说是不可见,而是由应用层来完成线程调度,对于操作系统来说仅仅是一个单线程的进程。图1 Java虚拟机的内部体系结构Java虚拟机在运行时,由主线程开始解释执行类文件中的指令,主线程在自己的线程栈中存放临时变量、参数变量等,一旦碰到生成新对象的new操作时,就会在堆空间内申请一块内存存放该类对象,而一旦程序从一个方法中退出后(退回到一个方法栈的栈底),虚拟机程序并不会立即释放Heap空间内的这块内存,这就是与C/C+程序所不同的地方,因为C/C+程序被加载程序的操作系统调用装载到内存中之后,程序的内存是由操作系统为之分配的4G的虚拟内存空间,而堆空间的使用也是由程序的内存分配子系统(malloc)来完成的,而这个子系统仅仅是向程序员提供了申请/释放内存的调用接口,查看C/C+编译器生成的汇编代码你会发现,如果你在一个函数中申请了一块内存,而没有在函数退出的地方没有释放的话,这块内存则会永远放在堆中,而对于你在函数中生明的类变量对象来说(非new来申请的指针对象),这个类对象的内存是在程序栈空间中分配的,一旦这个函数释放则对象空间自动释放,这样的内存泄漏正是Java竭力避免的,Java从发明之初就是考虑着如何将大部分应用程序员从繁重的内存管理工作中解脱出来,而由Java虚拟机使用称之为GC垃圾收集的模块来完成内存空间的管理。Java虚拟机在启动时会根据-Xms的参数值向操作系统一次性申请一块内存空间作为自己的堆,而随着后续程序的运行中内存需求的增加,则再向操作系统申请更多的内存加到自己的堆空间中。这个堆空间的最大值就是由-Xms指定的。一旦Java虚拟机发现应用程序申请的内存超过了堆内存的最大空间的话,Java就会抛出一个超出堆空间的异常。而当虚拟机在启动时如果申请不到足够的内存的话,则同样会抛出一个异常,启动失败。所有这些工作都是由Java虚拟机的内存管理模块来完成的,而Java的内存管理功能中最俱特色和重要的垃圾收集功能GC则是按照下面机制运行的。2.2 垃圾收集和线程同步Java的垃圾收集器就像一个兢兢业业的仓库保管员,他管理着虚拟机堆空间的清扫工作,接着上面描述的,一旦一个函数退出了它的栈,在该函数内声明的一个Java对象则会留在Java堆空间内,那么垃圾收集器会不会立即将这个对象的空间释放呢?答案是否定的,垃圾收集器只有在当堆空间占用到了一定程度时,或者程序比较空闲时才释放那些不再使用(遗漏)的对象空间。如果此时程序堆空间的使用不是很大,而程序又比较忙的话,则垃圾收集器就不会运行。当然程序员也可以通过在程序中调用JDK接口来申请虚拟机主动执行垃圾收集器。而垃圾收集器的工作和C/C+语言中明确的释放(delete)对象比起来有一个潜在的缺点,那就是,在垃圾收集的Java应用中程序员对于安排CPU时间进行内存回收缺乏控制,想要精确地预测出何时(甚至是否)进行垃圾收集、收集需要多长时间,基本上是不可能的。在早期的垃圾收集策略中,对象引用计数收集算法是最先被采用的,堆中的每个对象都有一个引用计数,当这个对象被赋值给一个变量,则该引用计数器加1,当一个对象超过了生命期或者被重新赋值的话,对象的引用减一,任何引用计数为0的对象都可以被当作垃圾收集。这样的算法一个固有的缺陷就是无法处理循环应用的情况,而且计数的增减也会带来开销。现代的Java虚拟机的实现中采用了压缩收集算法、拷贝收集算法、按代收集算法等,按代收集的算法是为了解决GC在回收对象空间的优先顺序的问题,在按代收集的算法中,GC总是优先回收那些短暂年幼的对象,而非一些寿命较长的对象。JVM堆被划分成多个小的区域子堆,每个子堆分别为不同“代”的对象服务,如果一个年幼的对象经历过好几次垃圾收集后都没有别收集掉,则它就变成一个年老的对象,会被转移到另一个存放寿命更长的对象的堆中。一切的改进就是本着让垃圾收集更快、更高效的目标进行的。在Java的语法里面,一个对象可以拥有终结方法,该方法是在垃圾收集器释放对象前必须执行的,程序员可以通过使用该方法来实现一些应用级清扫工作。可以在编程语言级支持多线程是Java语言的一大优势,这种支持主要集中在同步上。对于编译型语言C/C+来说,在语言级是没有多线程的概念的,程序员只能通过调用操作系统API来实现多线程应用。而在Java中线程的支持是通过一些预先定义好的关键字来实现,而且JDK开发包也为用户提供了线程创建、使用的很好的封装,程序员仅仅想使用普通的类一样继承一个特定的接口Runable或者继承一个已有的简单线程类Thread即可创建并使用Java的线程功能了。应用级线程一旦创建后,就交给了JVM管理,JVM内部维护这所有应用级以及JVM内部线程列表,用户可以通过指定JVM启动的参数来设置JVM的线程管理方式,是由JVM自己管理内部线程、完成线程通过工作,还是将应用线程直接绑到操作系统内核线程,并且由操作系统内核来完成线程同步等管理工作。下面会对这些参数一一进行介绍。Java内部的线程同步管理或线程调度是通过一种监视器的技术来实现的,基本上的原理如下,我们将监视器比喻成一座建筑,而其中一些特别的房间里面的数据在同一时间只能有一个“人”线程能够访问,当一个线程进入这个房间到它离开之前,它可以独占的操作其中的数据,我们将线程进入这个建筑叫做“进入监视器”,线程进入这个特殊的房间叫做“获得监视器”,离开房间时叫“释放监视器”,离开建筑时叫做“退出监视器”。监视器除了监控一些数据之外,还可以监控一些代码,这样的代码叫做监视区域,在同一监视器中,一块监视区域的代码在同一时间只能够被一个线程所访问。同步数据(类)或同步代码在Java程序中用Synchronized参数标明就可以了,从Java字节码编译器生成的虚拟机指令序列来看,编译器将操作指令monitorenter、monitorexit添加到具有Synchronized关键字的方法开始和结尾,而所有对具有Synchronized关键字的类数据的操作前后也都添加了monitorenter、monitorexit操作指令,这样在虚拟机指令序列(类文件代码)时JVM会调用monitorenter、monitorexit指令完成线程间的同步控制。图2 Java虚拟机线程同步监视器3 JAVA虚拟机参数分类说明3.1 Java虚拟机标准参数所谓的Java虚拟机标准参数指的就是所有的虚拟机实现都应该支持的参数,这部分参数基本上都是对虚拟机基本能力的调整,包括对运行模式、垃圾收集信息显示、显示版本信息、断言开关等,下面是以Solaris下1.4.2版本为例:参数使用说明备注-d32-d64指明该Java VM是运行与32位环境还是64位环境,默认是运行在32位环境下的,如果是配置了64位模式则需要操作系统也必须是64位的,当然CPU更需要是64位的。另外如果我们选择了-server参数,则就暗含了64位模式。因为64的CPU兼容32位操作系统,而64位操作系统又是兼容32位执行程序-client-server设置该JVM运行与Client 或者Server Hotspot模式,这两种模式从本质上来说是在JVM中运行不同的JIT(运行时编译模块)代码,并且两者在JVM内部的接口是一致的。客户端模式优化的是系统启动时间更快,而服务端模式的优化则更关注与系统的整体性能。一般来说Client选项用于GUI的应用,Server选项多用于后台服务器应用。另外两者在编译策略、垃圾收集策略、堆使用上也有所不同-hotspot在Hotspot类型的JVM中缺省使用,缺省为Client Hotspot模式。-cp-classpath指明JVM启动时要加载的类文件路径,Java虚拟机进程在启动时就会按照该参数后面指明的路径查找*.zip、*.jar、*.class文件,然后将这些包中的类文件加载到内存中。JVM加载类文件的顺序是-D=设置系统属性的值,该参数是的设计是为了满足Java应用程序员与JVM进行参数传递的手段之一,另一种是通过应用级参数(argument)来实现。Java程序员可以在程序内调用system.getProperty来获取用户通过-D参数传进来的系统属性信息。而命令行参数就是是JVM传递给main函数的调用参数-verbose:class-verbose:gc-verbose:jni打印详细信息,目前支持打印类加载信息:class、垃圾收集信息:gc、以及本地方法调用信息:jni,如果选择了此选项,则JVM会在命令行打印出上述信息;对于测试中的系统可以通过打开:gc开关,查看JVM每次垃圾收集的详细信息来判断系统内存消耗情况,如果系统垃圾收集的很频繁,而且每次都回收了大量的内存,则说明系统内存消耗很大,对象的创建和湮灭很频繁,而如果堆内存一直保持着增长的话,说明可能存在内存“泄漏”。-version-showversion-version选项是显示版本信息后JVM退出-showversion选项是显示版本信息后JVM继续运行-esa-enableassertions打开系统中每个类的断言开关该选项用于程序开发、调试过程-da-disableassertions关闭系统中每个类的断言开关该选项用于程序开发、调试过程表1 JVM 标准参数集3.2 Java虚拟机扩展参数所谓的Java虚拟机非标准参数指的就是一些特有的虚拟机实现所支持,下面以Solaris下1.4.2版本为例介绍一些扩展的虚拟机运行参数,其中对Hotspot VM相关的参数是我们进行性能调整的重点。参数使用说明备注-XmixedJVM执行模式的设置参数,混合模式即支持Hotspot即时编译的运行模式支持Hotspot的JVM缺省都是运行于混合模式的。-Xint设置JVM的执行模式为解释执行模式,纯解释执行的JVM对多数应用来说基本上时没有意义的,仅仅可能会在一些嵌入式系统中应用-Xbootclasspath设置初始类装载器的装载路径-Xnoclassgc设置不执行类垃圾收集-Xincgc设置是否启动火车垃圾收集算法-Xloggc:设置是否将GC信息写入日志文件-Xbatch设置不执行后台编译-Xms设置JVM启动时初始内存堆的大小-Xmx设置JVM启动后动态申请堆内存的最大堆空间-Xss设置JVM最大线程栈的空间大小-Xprof是否打印输出性能统计数据-Xrunhprof设置是否启动heap、cpu等性能统计监控功能(详细见下表)-Xdebug设置是否启动远程调试功能-Xfuture-Xrs设置是否屏蔽操作系统信号-Xcheck:jni设置对于本地调用是否执行额外检查表2 JVM 扩展参数集Java Hotspot、GC相关参数介绍,下面以Solaris下1.4.2版本为例,对于以 X 打头的非标准参数,是不能保证在每个JVM的实现中都支持的,而且关于这些参数行为的改变都不会得到通知,而对于以 XX 打头的非标准参数来说,它们中大多数都是和具体的操作系统支持有关的,而且有些甚至需要特殊的系统访问权限,而且这些参数也是遵循上述的改变不通知原则的。在使用中需要特别注意。参数使用说明备注-Xincgc在垃圾收集中使用火车算法-Xnoincgc在垃圾收集中不使用火车算法-XX:MaxHeapFreeRatio=JVM中堆空间的最大空闲百分比,缺省为70%,GC停止回收空间的上限值即:一旦当前堆内存空闲空间百分比超过总空间70时,GC暂停垃圾收集-X:MinHeapFreeRation=JVM中堆空间的最小空闲百分比,缺省为40%,GC开始回收空间的下限值即:一旦当前内存堆中内存空闲小于40%时,GC则恢复垃圾收集-Xint不启用即时编译(JIT)功能,仅仅解释执行缺省为不选的-XX:+UseBoundThreads绑定用户级线程(Solaris only),这个选项强制所有的Java线程在创建时都作为操作系统绑定的线程这个参数用来是否将JVM用户线程绑定到Solaris内核线程-XX:+UseParallelGC是否启用并行垃圾收集功能-XX:+UseAltSigs-XX:+PrintCompilation是否跟踪打印JIT编译信息-XX:+UseV8InstrsOnly-XX:MaxInlineSize=size限制动态编译的内联函数的虚拟机指令的最大数量-XX:FreqInlineSize=size限制经常使用的动态编译的函数的虚拟机指令的最大数量, -XX:-AllowUserSignalHandlers允许用户在应用层设置信号处理回调函数-XX:AltStackSize=16384预备信号栈的大小-XX:+MaxFDLimit设置JVM进程打开最大文件句柄数(Solaris only)-XX:-UseLWPSynchronization使用操作系统提供的轻量级线程LWP同步来代替基于Java虚拟机的线程的同步该参数的使用使得JVM 将线程同步的控制交由Solaris内核处理,从而代替了JVM内部的线程同步机制-XX:+UseThreadPriorities设置是否使用本地线程优先级-XX:-CITime设置Hotspot的一次即时编译所需要的最大时间-XX:-PrintTenuringDistribution打印使用年限-XX:+DisableExplicitGC屏蔽程序主动垃圾收集的函数system.gc()-XX:TargetSurvivorRatio=50设置执行垃圾收集GC后期望的空闲空间百分比-XX:CompileThreshold=10000设置方法是否进行即时编译的调用次数的下限值,-server选项的缺省值为10000,-client选项的缺省值为1500即:当该方法的被调用测试多于该值时,则该方法就会被JIT即时编译器编译成机器代码在内存中执行-XX:MaxNewSize=32m设置新一代的最大值按代垃圾收集中使用-XX:NewRatio=2新生代与老一代空间的比率,SUN Parc server中是2:1,Intel中是12:1-XX:NewSize=2228224新一代的缺省申请空间的值对于大行应用服务器系统这个值2K一般情况下需要调整大一些-XX:-UseSpinning-XX:PreBlockSpin=10-XX:ReservedCodeCacheSize=32m设置内存中保留代码缓冲区的大小-XX:SurvivorRatio=64-XX:ThreadStackSize=512每个线程栈大小(K),等于0时表示使用缺省值【Sparc: 512K,Solaris Intel: 256K,Sparc 64bit: 1024 其他的都为 0】-XX:+UseTLAB是否使用线程本地对象分配策略,SUN Sparc server时为true,其他为false-XX:-UseISM如果使用ISM选项可以获得如下的几个好处:1、使用大内存页来代替操作系统缺省的8K的页模式;2、将一些内存页锁定在内存中,而不必换出到硬盘如果系统使用ISM则系统文件/etc/system需要添加如下配置:set shmsys:shminfo_shmmax=0xffffffffset shmsys:shminfo_shmseg=32表3 JVM GC/Hotspot相关参数集注:即时编译是Hotspot中的概念,按代收集,火车算法等是属于GC中的概念。性能统计信息配置参数集,下面以Solaris下1.4.2版本为例。参数使用说明备注heap=打印JVM运行时堆统计信息到文件cpu=打印JVM运行时CPU使用统计信息到文件打印每个执行的方法的CPU占用百分比monitor=统计JVM Socket连接情况format=设置打印输出的格式为ascii或者二进制格式缺省为文本方式file=指定打印输出的文件名字缺省输出到java.hprof.txt文件中net=统计通过Socket发送消息的情况depth=指定跟踪的栈深度,缺省为4cutoff=lineno=指定跟踪的行数thread=指定是否跟踪线程doe=设置是否在JVM退出时导出所有的统计信息缺省为真表4 JVM 性能统计参数集注:对于一个代码规模量很大的服务器应用程序来说,如果通过这样的方式查看JVM运行统计信息的话,这样最后得到的统计数据将是一个非常庞大的文件,根据这样的统计文件来分析性能的话将是非常累人的工作,幸好现在有一些商用的Java Profile软件,如:Jprobe,OptimizeIT等,关于这些工具的讨论不在本文范畴之内,有兴趣的话可以参见本人写的一片关于Jprobe原理和使用的文章。4 JAVA应用性能测试调优经验总结4.1 GC调优参数的使用JVM中按代收集算法的基本原则是这样的,JVM堆空间被分成许多子堆,每个子堆用于存放不同代的对象,而当所有已经存在的堆中的各代对象都不能继续回收时,则新的子堆会被分配,用于存放新一代的对象,下面的这两个参数就是为按代收集设计的:-XX:NewRatio=2/新生代于老一代的空间比率-XX:NewSize=2228224/缺省时2K,对于应用服务器系统建议调整的大一些4K或8K-XX:MaxNewSize/新生代的最大空间-XX:MaxPermSize=64m/老一代的最大空间,缺省为64M,建议增加-XX:SurvivorRatio/GC时代子堆中的年老对象的比率-Xxincgc/是否在垃圾收集时启用火车算法-XX:+UseConcMarkSweepGC/是否启用并发收集算法-Xverifyheap/仅仅用于Debug版本,用于对GC数据分析-XX:TargetSurvivorRatio=50/GC收集后期望得到的被老一代占用的空间,建议不调整因为垃圾收集只是在各代的子堆满了的时候发生,总的堆的空间状况也会对垃圾收集产生重要的影响,JVM向操作系统申请更多的堆内存空间的前提是,堆中所有的年老的代的子堆都已经满了。-Xms/设置最小初始堆空间的大小-Xmx/设置最大堆空间的大小-XX:MinFreeHeapRatio=40/GC后JVM堆空间向操作系统缩小的比率。-XX:MaxHeapFreeRatio70/GC后JVM堆空间向操作系统扩张的比率。-XX:+AggressiveHeap/用于JVM运行于大内存模式下,JVM的堆空间至少在1G以/上,与-Xms、-Xmx不同时使用,慎用!会导致JVM极度消/耗内存在U-NICA这样的后台大型应用服务器系统来说,我们就采用了通过调整初始堆内存空间、堆增长量、增加新生代空间配置、使用并发收集算法、火车算法等方法来使的系统的垃圾收集能力得以优化。而

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论