JVM性能调优1:JVM性能调优理论及实践(收集整理)

本系列包括:java

JVM性能调优1:JVM性能调优理论及实践(收集整理)程序员

JVM性能调优2:JVM性能调优参数整理web

JVM性能调优3:JVM_堆溢出分析过程和命令算法

JVm性能调优4:GC日志分析windows

JVM性能调优5:Heap堆分析方法数组

 

 

注:本文部份内容收集整理了网上的资料。缓存

1.      内存结构服务器

1.1.     分代结构图网络

注意:多线程

在JVM中,非堆内存,根据模式不一样分为不一样的几个部分。

-Server下:非堆包括:持久代和代码缓存(Code cache)

-client下:非堆包括:持久代、代码缓存(Code cache)、Perm rw和perm ro。

2.      性能指标

对于垃圾收集的性能,主要有两个指标。

吞吐量(throughput)指用来进行垃圾收集以外工做所用的时间占总时间的百分比,通常要经过长时间的观察和测量。吞吐量包括了分配内存所花费的时间在内(通常来讲无需对分配进行调优)。

Throughput is the percentage of total time not spent in garbage collection,considered over long periods of time. Throughput includes time spent inallocation (but tuning for speed of allocation is generally not needed.) (from《Tuning GC with jdk 1.5》)

 

暂停(Pause)指因为进行垃圾收集而致使应用没法响应的时间。

Pauses are the times when an application appears unresponsive becausegarbage collection is occurring.

Footprint is the working set of a process, measured in pages and cachelines. On systems with limited physical memory or many processes, footprint maydictate scalability.      Promptnessis the time between when an object becomes dead and when the memory becomesavailable, an important consideration for distributed systems, including remotemethod invocation (RMI). (from《Tuning GC with jdk 1.5》)

用户对于垃圾收集有不一样的需求,例如,对于Web服务器应用来讲,吞吐量是要着重考虑的,而暂停时间可能因为网络的反应时间而不那么明显;而对于一个交互式图形界面的应用来讲,即便是短暂的暂停都会带来很是很差的用户体验。

In general, aparticular generation sizing chooses a trade-off between these considerations.For example, a very largeyoung generation may maximize throughput,but does so at the expense of footprint, promptness, and pause times.younggeneration pauses can be minimized by using a smallyoung generationat the expense of throughput. To a first approximation, the sizing of onegeneration does not affect the collection frequency and pause times for anothergeneration .(from《Tuning GC with jdk 1.5》)

一般来讲,如何设置代的大小是在这些考虑因素之间做出的一个权衡。例如,将新生代设置得很大会获得很好的吞吐性能,可是会增长暂停时间;反之,较小的新生代设置会减少暂停时间,可是下降了吞吐量。

一个代的大小不该该影响在其余代上进行垃圾收集的频率和暂停时间。

 

3.      引用类型

对象引用类型分为强引用、软引用、弱引用和虚引用

3.1.     强引用

就是咱们通常声明对象是时虚拟机生成的引用,强引用环境下,垃圾回收时须要严格判断当前对象是否被强引用,若是被强引用,则不会被垃圾回收。

3.2.     软引用

软引用通常被作为缓存来使用。与强引用的区别是,软引用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是否对软引用进行回收。若是剩余内存比较紧张,则虚拟机会回收软引用所引用的空间;若是剩余内存相对富裕,则不会进行回收。换句话说,虚拟机在发生OutOfMemory时,确定是没有软引用存在的。

3.3.     弱引用

弱引用与软引用相似,都是做为缓存来使用。但与软引用不一样,弱引用在进行垃圾回收时,是必定会被回收掉的,所以其生命周期只存在于一个垃圾回收周期内。

3.4.     虚引用

 

4.      内存分配回收次序

新生代是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。

新生区又分为两部分:伊甸区(Eden space)和幸存者区(Survivorpace),全部的类都是在enden被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。

当Eden的空间用完时,程序又须要建立对象,JVM的垃圾回收器将对enden区进行垃圾回收,将enden区中的再也不被其余对象所引用的对象进行销毁(次收集)。

而后将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收(次收集),而后移动到1区。那若是1区也满了呢?(次收集)

再移动到养老区。

新生代采用复制算法,old区采用标记清除算法。

不管是复制算法仍是标记清除算法,在垃圾收集期间都要暂停客户的应用程序(cms垃圾收集器除外,它在初始标记和从新标记时暂停,并发标记和并发清除时,客户线程不暂停)。

不管是复制算法仍是标记清除算法,在最开始,倒要标记活动的对象,即对象的可达性分析,在这里,必需要求对象是一致的(便可达性分析期间,内存状态是冻结的);在cms收集器是,在初始标记(对root对象标记时,要求冻结)冻结,但此时会产生浮动垃圾,即在并发标记时,由分配了新的对象(由于没有冻结)。

综述,基本过程是,复制算法:标记(暂停)-->复制(暂停,因对象地址发生变化);标记清除整理算法:标记(暂停)-->清除整理(消除碎片,暂停,因对象地址发生变化)。

对root对象标记很快,对内存扫描分析,可达性分析过程很慢。清除很慢(内存回收),内存整理、复制(慢)。

内存分配须要时间。

 

5.      对象标记算法(Object Marking Algorithms

5.1.     引用计数法(ReferenceCounting)

堆中每个对象都有一个引用计数。当新建立一个对象,或者有变量被赋值为这个对象的引用,则这个对象的引用计数加1;当一个对象的引用超过生存期或者被设置一个新的值时,这个对象的引用计数减1。当对象的引用计数变为0时,就能够被看成垃圾收集。

这种方法的好处是垃圾收集较快,适用于实时环境。缺点是这种方法没法监测出循环引用。例如对象A引用对象B,对象B也引用对象A,则这两个对象可能没法被垃圾收集器收集。所以这种方法是垃圾收集的早期策略,如今不多使用。

5.2.     根搜索算法(Garbage Collection Roots Tracing)

5.2.1.    基本思想

这种方法把每一个对象看做图中一个节点,对象之间的引用关系为图中各节点的邻接关系。垃圾收集器从一个或数个根结点遍历对象图,若是有些对象节点永远没法到达,则这个对象能够被看成垃圾回收。

容易发现,这种方法能够检测出循环引用,避免了引用计数法的缺点,较为经常使用。步骤以下:

  1. 选定一些对象,做为 GC Roots,组成基对象集;

  2. 由基对象集内的对象出发,搜索全部可达的对象;

  3. 其他的不可达的对象,就是能够被回收的对象。

    这里的“可达”与“不可达”与图论中的定义同样,全部的对象被看作点,引用被看作有向链接,整个引用关系就是一个有向图。在“引用计数法”中提到的循环引用,其实就是有向图中有环的状况,即构成“有向有环图”。引用计数法不适用于“有向有环图”,而根搜索算法适用于全部“有向图”,包括有环的和无环的。

5.2.2.    GCRoots

若是你的逻辑思惟够清晰,你会说“必定与选取基对象集的方法有关”。是的,没错。选取 GC Roots 组成基对象集,其实就是选取以下这些对象:

《深刻理解 Java 虚拟机:JVM高级特性与最佳实践》一书中提到的 GC Roots 为:

 

1.     方法区(Method Area,即 Non-Heap)中的类的 static 成员引用的对象,和 final成员引用的对象;

2.     Java方法栈(Java Method Stack)的局部变量表(Local Variable Table)中引用的对象;

3.     原生方法栈(Native Method Stack)中 JNI中引用的对象。

但显然不够全面,[参考2]中提到的要更全面:(March 6th,2012 update

1.     由系统类加载器加载的类相应的对象:这些类永远不会被卸载,且这些类建立的对象都是 static 的。注意用户使用的类加载器加载的类建立的对象,不属于 GC Roots,除非是 java.lang.Class 的相应实例有可能会称为其余类的 GC Roots。

2.     正在运行的线程。

3.     Java方法栈(Java Method Stack)的局部变量表(Local Variable Table)中引用的对象。

4.     原生方法栈(Native Method Stack)的局部变量表(Local Variable Table)中引用的对象。

5.     JNI中引用的对象。

6.     同步监控器使用的对象。

7.     由 JVM 的 GC控制的对象:这些对象是用于 JVM内部的,是实现相关的。通常状况下,可能包括系统类加载器(注意与“1”不同,“1”中是 objects created by the classes loaded bysystem class loaders,这里是 theobjects, corresponding instances of system class loaders)、JVM内部的一些重要的异常类的对象、异常句柄的预分配对象和在类加载过程当中自定义的类加载器。不幸的是,JVM并不提供这些对象的任何额外的详细信息。所以这些实现相关的内容,须要依靠分析来断定。

因此这个算法实施起来有两部分,第一部分就是到 JVM 的几个内存区域中“找对象”,第二部分就是运用图论算法

 

6.      垃圾回收算法

6.1.     标记-清除(Mark-Sweep)

此算法执行分两阶段。第一阶段从引用根节点开始标记全部被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法须要暂停整个应用,同时,会产生内存碎片。

6.2.     标记-整理(Mark-Compact)

此算法结合了“标记-清除”和“复制”两个算法的优势。也是分两阶段,第一阶段从根节点开始标记全部被引用对象,第二阶段遍历整个堆,把清除未标记对象而且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。

6.3.     复制(Copying)

此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另一个区域中。次算法每次只处理正在使用中的对象,所以复制成本比较小,同时复制过去之后还能进行相应的内存整理,不会出现“碎片”问题。固然,此算法的缺点也是很明显的,就是须要两倍内存空间

6.4.     增量收集算法

增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会形成较小的应用程序中断。

6.5.     分代收集算法

这种收集器把堆栈分为两个或多个域,用以存放不一样寿命的对象。虚拟机生成的新对象通常放在其中的某个域中。过一段时间,继续存在的对象将得到使用期并转入更长寿命的域中。分代收集器对不一样的域使用不一样的算法以优化性能。这样能够减小复制对象的时间。

6.6.     并发收集算法

并发收集器与应用程序同时运行。这些收集器在某点上(好比压缩时)通常都不得不中止其余操做以完成特定的任务,可是由于其余应用程序可进行其余的后台操做,因此中断其余处理的实际时间大大下降。

6.7.     并行收集器

并行收集器使用某种传统的算法并使用多线程并行的执行它们的工做。在多CPU机器上使用多线程技术能够显著的提升java应用程序的可扩展性。

6.8.     自适应收集器

根据程序运行情况以及堆的使用情况,自动选一种合适的垃圾回收算法。这样能够不局限与一种垃圾回收算法。

6.9.     火车增量算法

垃圾收集算法一个很大的缺点就是难以控制垃圾回收所占用的CPU时间,以及什么时候须要进行垃圾回收。火车算法是分代收集器所用的算法,目的是在成熟对象空间中提供限定时间的渐进收集。目前应用于SUN公司的Hotspot虚拟机上。

在火车算法中,内存被分为块,多个块组成一个集合。为了形象化,一节车箱表明一个块,一列火车表明一个集合,见图一

 

图一

注意每一个车箱大小相等,但每一个火车包含的车箱数不必定相等。垃圾收集以车箱为单位,收集顺序依次为1.1,1.2,1.3,1.4,2.1,2.2,2.3,3.1,3.2,3.3。这个顺序也是块被建立的前后顺序。

垃圾收集器先从块1.1开始扫描直到1.4,若是火车1四个块中的全部对象没有被火车2和火车3的对象引用,而只有火车1内部的对象相互引用,则整个火车1都是垃圾,能够被回收。

如图二,车箱1.1中有对象A和对象B,1.3中有对象C,1.4中有对象D,车箱2.2中有对象E,车箱3.3中有对象F。在火车1中,对象C引用对象A,对象B引用对象D,可见,火车2和火车3没有引用火车1的对象,则整个火车1都是垃圾。

图二

 

若是火车1中有对象被其它火车引用,见图三,扫描车箱1.1时发现对象A被火车2中的E引用,则将对象A从车箱1.1转移到车箱2.2,而后扫描A引用的对象D,把D也转移到车箱2.2,而后扫描D,看D是否引用其它对象,若是引用了其它对象则也要转移,依次类推。扫描完火车1的全部对象后,剩下的没有转移的对象都是垃圾,能够把整个火车1都做为垃圾回收。注意若是在转移时,若是车箱2.2空间满了,则要在火车2末尾开辟新的车箱2.4,将新转移的对象都放到2.4,即火车的尾部)

图三

补充说明:垃圾回收器一次只扫描一个车箱。图三中的对象B与C并非当即被回收,而是先会被转移到火车1的尾部车箱。即扫描完1.1后,B被转移到火车1尾部,扫描完1.3后,C被转移到车尾。等垃圾收集器扫描到火车1尾部时,若是仍然没有外部对象引用它们,则B和C会被收集。

火车算法最大的好处是它能够保证大的循环结构能够被彻底收集,由于成为垃圾的循环结构中的对象,不管多大,都会被移入同一列火车,最终一块儿被收集。还有一个好处是这种算法在大多数状况下能够保证一次垃圾收集所耗时间在必定限度以内,由于一次垃圾回收只收集一个车箱,而车箱的大小是有限度的。

 

7.      触发垃圾收集的条件

因为对象进行了分代处理,所以垃圾回收区域、时间也不同。GC有两种类型:Scavenge GC和Full GC。

7.1.     次收集ScavengeGC

通常状况下,当Enden区对象已满,或当新对象生成,而且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,而且把尚且存活的对象移动到Survivor区。而后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。由于大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,因此Eden区的GC会频繁进行。于是,通常在这里须要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

对Survivor区,当达到设置的预约值(默认50%),则进行一次垃圾次收集。

7.2.     全收集FullGC

对整个堆进行整理,包括Young、Tenured和Perm。Full GC由于须要对整个对进行回收,因此比Scavenge GC要慢,所以应该尽量减小Full GC的次数。在对JVM调优的过程当中,很大一部分工做就是对于FullGC的调节。有以下缘由可能致使Full GC:

·年老代(Tenured)被写满

·持久代(Perm)被写满

· System.gc()被显示调用

·上一次GC以后Heap的各域分配策略动态变化

 

8.      垃圾收集器类型

8.1.     串行收集器

用单线程处理全部垃圾回收工做,由于无需多线程交互,因此效率比较高。可是,也没法使用多处理器的优点,因此此收集器适合单处理器机器。固然,此收集器也能够用在小数据量(100M左右)状况下的多处理器机器上。可使用-XX:+UseSerialGC打开。

8.2.     并行收集器

注:图有问题,是并发垃圾收集器的图。

并行垃圾回收,所以能够减小垃圾回收时间。通常在多线程多处理器机器上使用。

8.3.     并发垃圾收集

并发收集器主要减小年老代的暂停时间,他在应用不中止的状况下使用独立的垃圾回收线程,跟踪可达对象。在每一个年老代垃圾回收周期中,在收集初期并发收集器会对整个应用进行简短的暂停,在收集中还会再暂停一次。第二次暂停会比第一次稍长,在此过程当中多个线程同时进行垃圾回收工做。

浮动垃圾:因为在应用运行的同时进行垃圾回收,因此有些垃圾可能在垃圾回收进行完成时产生,这样就形成了“Floating Garbage”,这些垃圾须要在下次垃圾回收周期时才能回收掉。因此,并发收集器通常须要20%的预留空间用于这些浮动垃圾。

Concurrent Mode Failure:并发收集器在应用运行时进行收集,因此须要保证堆在垃圾回收的这段时间有足够的空间供程序使用,不然,垃圾回收还未完成,堆空间先满了。这种状况下将会发生“并发模式失败”,此时整个应用将会暂停,进行垃圾回收。

启动并发收集器:由于并发收集在应用运行时进行收集,因此必须保证收集完成以前有足够的内存空间供程序使用,不然会出现“Concurrent Mode Failure”。经过设置-XX:CMSInitiatingOccupancyFraction=<N>指定old区达到百分之多少时开始执行并发收集。

9.      垃圾收集器介绍

9.1.     串行垃圾收集

Serial Collector是指任什么时候刻都只有一个线程进行垃圾收集,这种策略有一个名字“stop the whole world",它须要中止整个应用的执行。这种类型的收集器适合于单器CPU的机器。

Serial Copying Collector

此种GC用-XX:UseSerialGC选项配置,它只用于新生代对象的收集。1.5.0之后.

-XX:MaxTenuringThreshold来设置对象复制的次数。当eden空间不够的时候,GC会将eden的活跃对象和一个名叫From survivor空间中尚不够资格放入Old代的对象复制到另一个名字叫To Survivor的空间。而此参数就是用来讲明到底From survivor中的哪些对象不够资格,假如这个参数设置为31,那么也就是说只有对象复制31次之后才算是有资格的对象。

这里须要注意几个个问题:

  • From Survivor和To survivor的角色是不断的变化的,同一时间只有一块空间处于使用状态,这个空间就叫作From Survivor区,当复制一次后角色就发生了变化。

  • 若是复制的过程当中发现To survivor空间已经满了,那么就直接复制到old generation.

  • 比较大的对象也会直接复制到Old generation,在开发中,咱们应该尽可能避免这种状况的发生。

     

     

    并行垃圾收集(Parallel Collector)

    Parallel Copying Collector

    -XX:+UseParNewGC用来设置年轻代为并发收集【多CPU】,若是你的服务器有多个CPU,你能够开启此参数;开启此参数,多个CPU可并发进行垃圾回收,可提升垃圾回收的速度。此参数和-XX:ParallelGCThreads搭配使用。适用于1.4之后版本。

 

Parallel Mark-Compact Collector

此种GC用-XX:+UseParallelOldGC参数配置,此GC主要用于老生代对象的收集。适用于1.6.0之后版本。

 

Parallel scavenging Collector

-XX:+UseParallelGC它是对新生代对象的垃圾收集器。年轻代使用并行收集,而年老代仍旧使用串行收集。可提升系统的吞吐量。此参数和-XX:ParallelGCThreads搭配使用。适用于1.4之后版本。它比较适合于对吞吐量高于暂停时间的场合。

采用多线程并行(Parallel)进行垃圾收集。

 

9.3.     并发垃圾收集器(Concurrent Collector)

此种GC能够用参数-XX:+UseConcMarkSweepGC配置,此GC主要用于老生代和Perm代的收集。

Concurrent Collector经过并发的方式进行垃圾收集,这样就减小了垃圾收集器收集一次的时间,这种GC在实时性要求高于吞吐量的时候比较有用。

在应用运行的同时,并发(Concurrent)进行垃圾收集。

  1. 配置垃圾回收线程数量

             -XX:ParallelGCThreads年轻代并行垃圾收集的前提下(对并发也有效果)的线程数,增长并行度,即:同时多少个线程一块儿进行垃圾回收。此值最好配置与处理器数目相等。
    例如:-XX:ParallelGCThreads=2

  2. 配置垃圾收集器须要注意的地方

    垃圾收集器不可重复配置,例如已经配置了新生代并行收集(-XX:+UseParNewGC),此时不能配置任何对新生代的垃圾收集。能够配置对旧生代和持久对象的垃圾收集。

    例如:

    -XX:+UseParNewGC-XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=2

    可组合适用。

    增量

    配合并发垃圾收集,适用于单cpu的架构,sun不建议使用。

     

    自适应

    自适应垃圾收集,运行在并行垃圾收集上。在并行收集时对于收集时间、分配比例、收集以后堆的空闲空间等数据进行统计分析,而后以此为依据调整新生代和旧生代的大小以达到最佳效果。

     

     

    小结

             从J2SE平台1.4.2版本开始,加入了另外3种垃圾收集器,都是着重提升吞吐能力,下降垃圾收集时的暂停时间。

             1. 吞吐收集器(throughput collector):命令行参数:-XX:+UseParallelGC。在新生代使用并行收集策略,在旧生代和默认收集器相同。

             吞吐收集器和默认的收集器相似,都是分代收集器。不一样之处就在于吞吐收集器用多线程进行次要收集,

            从J2SE平台1.4.1版本开始,吞吐收集器就具备了一个特征,就是大小自适应(参数-XX:

    +UseAdaptiveSizePolicy),这个选项默认是打开的。该特征对于收集时间、分配比例、收集以后   堆的空闲空间等数据进行统计分析,而后以此为依据调整新生代和旧生代的大小以达到最佳效果。可使用-verbose:gc来查看堆的大小。

             -XX:+AggressiveHeap选项会检测主机的资源(内存大小、处理器数量),而后调整相关的参数,使得长时间运行的、内存申请密集的任务可以以最佳状态运行。该选项最初是为拥有大量内存和不少处理器的主机而设计的,可是从J2SE1.4.1以及其后继版原本看,即便是对于那些只有4颗CPU的       主机,该选项都是颇有帮助的。所以,吞吐收集器(-XX:+UseParallelGC)、大小自适应 (-XX:+UseAdaptiveSizePolicy)以及本选项(-XX:+AggressiveHeap)常常结合在一块儿使用。要使    用本选项,主机上至少要有256M的物理内存,堆内存的最初大小是基于物理内存计算出来的,而后 会根据须要尽量的利用物理内存。

           2. 并发收集器(concurrent low pause collector):命令行参数:-XX:+UseConcMarkSweepGC。在旧生代使用并发收集策略,大部分收集工做都是和应用并发进行的,在进行收集的时候,应用的暂停时间很短。若是综合使用-XX:+UseParNewGC和-XX:+UseConcMarkSweepGC,那么在新生代上使用并行的收集策略。

             3. 增量收集器(incremental low pause collector):命令行参数:-Xincgc。使用增量收集器要谨慎,他只是在每次进行次要收集的时候对旧生代进行一部分的收集,这样就把主要收集所带来的较长时间的停顿分散到屡次的次要收集。可是,考虑到总共的吞吐,可能比旧生代上默认的收集还要慢。

    注意,-XX:+UseParallelGC和XX:+UseConcMarkSweepGC不能同时使用。对于J2SE1.4.2版本会检查垃圾收集相关参数组合的合法性,可是对于以前的版本没有这个检查,可能会致使不可预知的错误。

    垃圾回收器相关参数

    串行垃圾收集器参数

     

参数

说明

-XX:+UseSerialGC

设置串行收集器。

 

 

 

10.2.  并行垃圾收集器参数

参数

说明

-XX:+UseParallelGC

选择垃圾收集器为并行收集器,此配置仅对年轻代有效,即上述配置下,年轻代使用并行收集,而老年代仍旧使用串行收集。采用了多线程并行管理和回收垃圾对象,提升了回收效率,提升了服务器的吞吐量,适合于多处理器的服务器。

-XX:ParallelGCThreads

配置并行收集器的线程数,即:同时多少个线程一块儿进行垃圾回收。此值最好配置与处理器数目相等。

-XX:+UseParallelOldGC

采用对于老年代并发收集的策略,能够提升收集效率。JDK6.0支持对老年代并行收集。

-XX:MaxGCPauseMillis

设置每次年轻代并行收集最大暂停时间,若是没法知足此时间,JVM会自动调全年轻代大小以知足此值。

-XX:+UseAdaptiveSizePolicy

设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低响应时间或者收集频率等,此值建议使用并行收集器时,一直打开。

-XX:+UseParNewGC

指定在 New Generation使用 parallel collector,是 UseParallelGC的 gc的升级版本 ,有更好的性能或者优势 ,能够和 CMS gc一块儿使用

 

10.3.  并发垃圾收集器参数

参数

说明

-XX:+UseConcMarkSweepGC

指定在老年代使用 concurrent cmark sweep gc。gc thread和 app thread并行 (在 init-mark和 remark时 pause app thread)。app pause时间较短 ,适合交互性强的系统 ,如 web server。它能够并发执行收集操做,下降应用中止时间,同时它也是并行处理模式,能够有效地利用多处理器的系统的多进程处理。

-XX:+UseCMSCompactAtFullCollection

打开对老年代的压缩。可能会影响性能,可是能够消除碎片,在FULL GC的时候,压缩内存, CMS是不会移动内存的,所以,这个很是容易产生碎片,致使内存不够用,所以,内存的压缩这个时候就会被启用。增长这个参数是个好习惯。

-XX:+CMSIncrementalMode

设置为增量模式。适用于单CPU状况

-XX:CMSFullGCsBeforeCompaction

因为并发收集器不对内存空间进行压缩、整理,因此运行一段时间之后会产生“碎片”,使得运行效率下降。此值设置运行多少次GC之后对内存空间进行压缩、整理。

-XX:+CMSClassUnloadingEnabled

使CMS收集持久代的类,而不是fullgc

-XX:+CMSPermGenSweepingEnabled

使CMS收集持久代的类,而不是fullgc。

-XX:-CMSParallelRemarkEnabled

在使用 UseParNewGC的状况下 ,尽可能减小 mark的时间。

-XX:CMSInitiatingOccupancyFraction

说明老年代到百分之多少满的时候开始执行对老年代的并发垃圾回收(CMS),这个参数设置有很大技巧,基本上知足公式:

(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn

时就不会出现promotion failed。在个人应用中Xmx是6000,Xmn是500,那么Xmx-Xmn是5500兆,也就是老年代有5500兆,CMSInitiatingOccupancyFraction=90说明老年代到90%满的时候开始执行对老年代的并发垃圾回收(CMS),这时还剩10%的空间是5500*10%=550兆,因此即便Xmn(也就是年轻代共500兆)里全部对象都搬到老年代里,550兆的空间也足够了,因此只要知足上面的公式,就不会出现垃圾回收时的promotion failed;

若是按照Xmx=2048,Xmn=768的比例计算,则CMSInitiatingOccupancyFraction的值不能超过40,不然就容易出现垃圾回收时的promotion failed。

-XX:+UseCMSInitiatingOccupancyOnly

指示只有在老年代在使用了初始化的比例后 concurrent collector 启动收集

11.   JVM内存溢出类型

对于JVM的内存写过的文章已经有点多了,并且有点烂了,不过说那么多大多数在解决OOM的状况,于此,本文就只阐述这个内容,携带一些分析和理解和部分扩展内容,也就是JVM宕机中的一些问题,OK,下面说下OOM的常见状况:

第一类内存溢出,就是堆栈溢出:关键字:java.lang.OutOfMemoryError: ......javaheap space.....

也就是当你看到heap相关的时候就确定是堆栈溢出了,此时若是代码没有问题的状况下,适当调整-Xmx和-Xms是能够避免的,不过必定是代码没有问题的前提,为何会溢出呢,要么代码有问题,要么访问量太多而且每一个访问的时间太长或者数据太多,致使数据释放不掉,由于垃圾回收器是要找到那些是垃圾才能回收,这里它不会认为这些东西是垃圾,天然不会去回收了;主意这个溢出以前,可能系统会提早先报错关键字为:

java.lang.OutOfMemoryError:GC over headlimit exceeded

这种状况是当系统处于高频的GC状态,并且回收的效果依然不佳的状况,就会开始报这个错误,这种状况通常是产生了不少不能够被释放的对象,有多是引用使用不当致使,或申请大对象致使,可是java heap space的内存溢出有可能提早不会报这个错误,也就是可能内存就直接不够致使,而不是高频GC.

 

第二类内存溢出,PermGen的溢出,或者PermGen满了的提示,你会看到这样的关键字:关键信息为:java.lang.OutOfMemoryError: PermGenspace

缘由:系统的代码很是多或引用的第三方包很是多、或代码中使用了大量的常量、或经过intern注入常量、或者经过动态代码加载等方法,致使常量池的膨胀,虽然JDK 1.5之后能够经过设置对永久带进行回收,可是咱们但愿的是这个地方是不作GC的,它够用就行,因此通常状况下今年少作相似的操做,因此在面对这种状况经常使用的手段是:增长-XX:PermSize和-XX:MaxPermSize的大小。

 

第三类内存溢出:在使用ByteBuffer中的allocateDirect()的时候会用到,不少javaNIO的框架中被封装为其余的方法溢出关键字:java.lang.OutOfMemoryError: Directbuffer memory

若是你在直接或间接使用了ByteBuffer中的allocateDirect方法的时候,而不作clear的时候就会出现相似的问题,常规的引用程序IO输出存在一个内核态与用户态的转换过程,也就是对应直接内存与非直接内存,若是常规的应用程序你要将一个文件的内容输出到客户端须要经过OS的直接内存转换拷贝到程序的非直接内存(也就是heap中),而后再输出到直接内存由操做系统发送出去,而直接内存就是由OS和应用程序共同管理的,而非直接内存能够直接由应用程序本身控制的内存,jvm垃圾回收不会回收掉直接内存这部分的内存,因此要注意了哦。

若是常常有相似的操做,能够考虑设置参数:-XX:MaxDirectMemorySize

 

第四类内存溢出错误:溢出关键字:java.lang.StackOverflowError

这个参数直接说明一个内容,就是-Xss过小了,咱们申请不少局部调用的栈针等内容是存放在用户当前所持有的线程中的,线程在jdk 1.4之前默认是256K,1.5之后是1M,若是报这个错,只能说明-Xss设置得过小,固然有些厂商的JVM不是这个参数,本文仅仅针对Hotspot VM而已;不过在有必要的状况下能够对系统作一些优化,使得-Xss的值是可用的。

 

第五类内存溢出错误:溢出关键字:java.lang.OutOfMemoryError: unable tocreate new native thread

上面第四种溢出错误,已经说明了线程的内存空间,其实线程基本只占用heap之外的内存区域,也就是这个错误说明除了heap之外的区域,没法为线程分配一块内存区域了,这个要么是内存自己就不够,要么heap的空间设置得太大了,致使了剩余的内存已经很少了,而因为线程自己要占用内存,因此就不够用了,说明了缘由,如何去修改,不用我多说,你懂的。

 

第六类内存溢出:溢出关键字java.lang.OutOfMemoryError: request {}byte for {}out of swap

这类错误通常是因为地址空间不够而致使。

六大类常见溢出已经说明JVM中99%的溢出状况,要逃出这些溢出状况很是困难,除非一些很怪异的故障问题会发生,好比因为物理内存的硬件问题,致使了code cache的错误(在由byte code转换为native code的过程当中出现,可是几率极低),这种状况内存会被直接crash掉,相似还有swap的频繁交互在部分系统中会致使系统直接被crash掉,OS地址空间不够的话,系统根本没法启动,呵呵;JNI的滥用也会致使一些本地内存没法释放的问题,因此尽可能避开JNI;socket链接数据打开过多的socket也会报相似:IOException: Too many open files等错误信息。

JNI就不用多说了,尽可能少用,除非你的代码太牛B了,我无话可说,呵呵,这种内存若是没有在被调用的语言内部将内存释放掉(如C语言),那么在进程结束前这些内存永远释放不掉,解决办法只有一个就是将进程kill掉。

另外GC自己是须要内存空间的,由于在运算和中间数据转换过程当中都须要有内存,因此你要保证GC的时候有足够的内存哦,若是没有的话GC的过程将会很是的缓慢。

 

12.   JAVA虚拟机参数分类说明

12.1.  标准参数(-)

所谓的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<name>=<value>

设置系统属性的值,该参数是的设计是为了知足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标准参数集

 

12.2.  扩展参数(-X)

 

所谓的Java虚拟机非标准参数指的就是一些特有的虚拟机实现所支持,下面以Solaris下1.4.2版本为例介绍一些扩展的虚拟机运行参数,其中对Hotspot VM相关的参数是咱们进行性能调整的重点。

 

参数

使用说明

备注

-Xmixed

JVM执行模式的设置参数,混合模式即支持Hotspot即时编译的运行模式

支持Hotspot的JVM缺省都是运行于混合模式的。

-Xint

设置JVM的执行模式为解释执行模式,纯解释执行的JVM对多数应用来讲基本上时没有意义的,仅仅可能会在一些嵌入式系统中应用

 

-Xbootclasspath

设置初始类装载器的装载路径

 

-Xnoclassgc

设置不执行类垃圾收集

 

-Xincgc

设置是否启动火车垃圾收集算法

 

-Xloggc:<file>

设置是否将GC信息写入日志文件

 

-Xbatch

设置不执行后台编译

 

-Xms<size>

设置JVM启动时初始内存堆的大小

 

-Xmx<size>

设置JVM启动后动态申请堆内存的最大堆空间

 

-Xss<size>

设置JVM最大线程栈的空间大小

 

-Xprof

是否打印输出性能统计数据

 

-Xrunhprof

设置是否启动heap、cpu等性能统计监控功能(详细见下表)

 

-Xdebug

设置是否启动远程调试功能

 

-Xfuture

 

 

-Xrs

设置是否屏蔽操做系统信号

 

-Xcheck:jni

设置对于本地调用是否执行额外检查

 

 

                  1. JVM扩展参数集

Java Hotspot、GC相关参数介绍,下面以Solaris下1.4.2版本为例,对于以–X打头的非标准参数,是不能保证在每一个JVM的实现中都支持的,并且关于这些参数行为的改变都不会获得通知。

 

12.3.  非稳定(Stable)参数(-XX)

而对于以–XX打头的非标准参数来讲,它们中大多数都是和具体的操做系统支持有关的,并且有些甚至须要特殊的系统访问权限,并且这些参数也是遵循上述的改变不通知原则的。在使用中须要特别注意。

在Sun的文档中,又分为三类:

行为参数(Behavioral Options):用于改变jvm的一些基础行为;
性能调优(Performance Tuning):用于jvm的性能调优;
调试参数(Debugging Options):通常用于打开跟踪、打印、输出等jvm参数,用于显示jvm更加详细的信息;

 

12.3.1. 行为参数

参数及其默认值

描述

-XX:-DisableExplicitGC

禁止调用System.gc();但jvm的gc仍然有效

-XX:+MaxFDLimit

最大化文件描述符的数量限制

-XX:+ScavengeBeforeFullGC

新生代GC优先于Full GC执行

-XX:+UseGCOverheadLimit

在抛出OOM以前限制jvm耗费在GC上的时间比例

-XX:-UseConcMarkSweepGC

对老生代采用并发标记交换算法进行GC

-XX:-UseParallelGC

启用并行GC

-XX:-UseParallelOldGC

对Full GC启用并行,当-XX:-UseParallelGC启用时该项自动启用

-XX:-UseSerialGC

启用串行GC

-XX:+UseThreadPriorities

启用本地线程优先级

 

上面表格中黑体的三个参数表明着jvm中GC执行的三种方式,即串行、并行、并发;

串行(SerialGC是jvm的默认GC方式,通常适用于小型应用和单处理器,算法比较简单,GC效率也较高,但可能会给应用带来停顿;

并行(ParallelGC是指GC运行时,对应用程序运行没有影响,GC和app二者的线程在并行执行,这样能够最大限度不影响app的运行;

并发(ConcMarkSweepGC是指多个线程并发执行GC,通常适用于多处理器系统中,能够提升GC的效率,但算法复杂,系统消耗较大;

 

12.3.2. 性能调优

参数及其默认值

描述

-XX:LargePageSizeInBytes=4m

设置用于Java堆的大页面尺寸

-XX:MaxHeapFreeRatio=70

GC后java堆中空闲量占的最大比例

-XX:MaxNewSize=size

新生成对象能占用内存的最大值

-XX:MaxPermSize=64m

老生代对象能占用内存的最大值

-XX:MinHeapFreeRatio=40

GC后java堆中空闲量占的最小比例

-XX:NewRatio=2

新生代内存容量与老生代内存容量的比例

-XX:NewSize=2.125m

新生代对象生成时占用内存的默认值

-XX:ReservedCodeCacheSize=32m

保留代码占用的内存容量

-XX:ThreadStackSize=512

设置线程栈大小,若为0则使用系统默认值

-XX:+UseLargePages

使用大页面内存

 

12.3.3. 调试/打印信息参数

参数及其默认值

描述

-XX:-CITime

打印消耗在JIT编译的时间

-XX:ErrorFile=./hs_err_pid<pid>.log

保存错误日志或者数据到文件中

-XX:-ExtendedDTraceProbes

开启solaris特有的dtrace探针

-XX:HeapDumpPath=./java_pid<pid>.hprof

指定导出堆信息时的路径或文件名

-XX:HeapDumpOnOutOfMemoryError

当首次遭遇OOM时导出此时堆中相关信息

-XX:OnError="<cmd args>;<cmd args>"

出现致命ERROR以后运行自定义命令

-XX:OnOutOfMemoryError="<cmd args>;<cmd args>"

当首次遭遇OOM时执行自定义命令

-XX:-PrintClassHistogram

遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同

-XX:-PrintConcurrentLocks

遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同

-XX:-PrintCommandLineFlags

打印在命令行中出现过的标记

-XX:-PrintCompilation

当一个方法被编译时打印相关信息

-XX:-PrintGC

每次GC时打印相关信息

-XX:-PrintGC Details

每次GC时打印详细信息

-XX:-PrintGCTimeStamps

打印每次GC的时间戳

-XX:-TraceClassLoading

跟踪类的加载信息

-XX:-TraceClassLoadingPreorder

跟踪被引用到的全部类的加载信息

-XX:-TraceClassResolution

跟踪常量池

-XX:-TraceClassUnloading

跟踪类的卸载信息

-XX:-TraceLoaderConstraints

跟踪类加载器约束的相关信息

 

12.3.4. 参数汇总(不含调试和垃圾收集参数)

参数

使用说明

备注

-XX:+AggressiveHeap

长时间大内存使用的优化,能检查计算资源(内存,处理器数量),至少须要256MB内存,大量的CPU/内存,(在1.4.1在4CPU的机器上已经显示有提高)

 

-XX:+AggressiveOpts

加快编译

 

-XX:-AllowUserSignal

Handlers

容许用户在应用层设置信号处理回调函数

 

-XX:AltStackSize=16384

预备信号栈的大小

 

-XX:-CITime

设置Hotspot的一次即时编译所须要的最大时间

 

-XX:CompileThreshold

=10000

设置方法是否进行即时编译的调用次数的下限值,-server选项的缺省值为10000,-client选项的缺省值为1500

即:当该方法的被调用测试多于该值时,则该方法就会被JIT即时编译器编译成机器代码在内存中执行

-XX:+DisableExplicitGC

屏蔽程序主动垃圾收集的函数system.gc()

 

-XX:FreqInlineSize=size

限制常用的动态编译的函数的虚拟机指令的最大数量,

 

-Xincgc

在垃圾收集中使用火车算法

 

-Xint

不启用即时编译(JIT)功能,仅仅解释执行

缺省为不选的

-XX:LargePageSizeInBytes

内存页的大小,不可设置过大,会影响Perm的大小。

 

 

 

 

-XX:MaxHeapFreeRatio

=<Maximum>

JVM中堆空间的最大空闲百分比,缺省为70%,GC中止回收空间的上限值

即:一旦当前堆内存空闲空间百分比超过总空间70%时,GC暂停垃圾收集

-XX:MinHeapFreeRatio

=<Minimum>

JVM中堆空间的最小空闲百分比,缺省为40%,GC开始回收空间的下限值

即:一旦当前内存堆中内存空闲小于40%时,GC则恢复垃圾收集

-XX:MaxInlineSize=size

限制动态编译的内联函数的虚拟机指令的最大数量

 

-XX:+MaxFDLimit

设置JVM进程打开最大文件句柄数(Solaris only)

 

-XX:MaxNewSize=32m

在为新生代对象分配内存值,每块内存的最大值。

按代垃圾收集中使用

-XX:MaxTenuringThreshold=30

在存活区之间Copy的次数,超过该次数则移至Old区。

 

-Xmn

为新生代分配的内存大小。

 

-XX:NewRatio=2

新生代与老一代空间的比率,-XX:NewRatio = 2表示 Eden:old = 1:2。SUN Parc –server中是2:1,Intel中是12:1。

 

-XX:NewSize=2228224

新一代的缺省申请空间的值

对于大型应用服务器系统这个值2K通常状况下须要调整大一些

-Xnoincgc

在垃圾收集中不使用火车算法

 

-XX:PreBlockSpin=10

 

 

-XX:-PrintTenuring

Distribution

打印使用年限

 

-XX:ReservedCodeCache

Size=32m

设置内存中保留代码缓冲区的大小

 

-XX:SoftRefLRUPolicyMSPerMB

相对于客户端模式的虚拟机(-client选项),当使用服务器模式的虚拟机时(-server选项),对于软引用(soft reference)的清理力度要稍微差一些。能够经过增大-XX:SoftRefLRUPolicyMSPerMB来下降收集频率。默认值是 1000,也就是说每秒一兆字节。Soft reference在虚拟机中比在客户集中存活的更长一些。其清除频率能够用命令行参数-XX:SoftRefLRUPolicyMSPerMB=<N>来控制,这能够指定每兆堆空闲空间的 soft reference保持存活(一旦它不强可达了)的毫秒数,这意味着每兆堆中的空闲空间中的 soft reference会(在最后一个强引用被回收以后)存活1秒钟。注意,这是一个近似的值,由于 soft reference只会在垃圾回收时才会被清除,而垃圾回收并不总在发生。

 

-XX:SurvivorRatio=64

存活区和eden区所占的比率:2:64

 

-XX:TargetSurvivorRatio

=50

该值是一个百分比,控制容许使用的生存区空间的比例,默认值是50。即占到50%,则执行Copy策略。该参数设置较大的话可提升对survivor空间的使用率。

 

-XX:ThreadStackSize

=512

每一个线程栈大小(K),等于0时表示使用缺省值【Sparc: 512K,Solaris Intel: 256K,Sparc 64bit: 1024其余的都为0】

 

-XX:+UseBoundThreads

绑定用户级线程(Solaris only),这个选项强制全部的Java线程在建立时都做为操做系统绑定的线程

这个参数用来是否将JVM用户线程绑定到Solaris内核线程

-XX:+UseAltSigs

 

 

-XX:+UseV8InstrsOnly

 

 

-XX:-UseLWPSynchroniza

tion

使用操做系统提供的轻量级线程LWP同步来代替基于Java虚拟机的线程的同步

该参数的使用使得JVM将线程同步的控制交由Solaris内核处理,从而代替了JVM内部的线程同步机制

-XX:+UseThreadPriorities

设置是否使用本地线程优先级

 

-XX:-UseSpinning

 

 

-XX:+UseTLAB

是否使用线程本地对象分配策略,SUN Sparc –server时为true,其余为false

 

-XX:-UseISM

若是使用ISM选项能够得到以下的几个好处:一、使用大内存页来代替操做系统缺省的8K的页模式;

二、将一些内存页锁定在内存中,而没必要换出到硬盘

 

若是系统使用ISM则系统文件/etc/system须要添加以下配置:

set shmsys:

shminfo_shmmax

=0xffffffff

set shmsys:

shminfo_shmseg=32

-XX:+UseFastAccessorMethods

原始类型的快速优化,get,set方法转成本地代码。

 

-XX:+UseBiasedLocking

锁机制的性能改善。

 

 

                  1. JVM GC/Hotspot相关参数集

 

注:即时编译是Hotspot中的概念,按代收集,火车算法等是属于GC中的概念。

 

13.   项目调优经验1

  1. CMS垃圾收集器

    Date:2010-12-24

    JVM参数:

 

-Xss2M -XX:PermSize=128M -XX:MaxPermSize=128M -Xms2G -Xmx2G -Xmn832M -XX:SurvivorRatio=6 -XX:TargetSurvivorRatio=80 -XX:ParallelGCThreads=8 -XX:+UseConcMarkSweepGC

 

观察分析:

  1. 新生代每次执行一次垃圾收集,旧生代增长一点:

旧生代:489,711 Kbà489,740Kb ;

新生代(638,976kb):651,878Kbà29,00kb

存活区(106,496kb):约10,000kbà5,000kb

上述数听说明:对象在存活只存活一个周期,就被移到旧生代;相对应新生代每次收集存活区的最高利用率只有10%,根据上述参数能够把存活区Copy次数改成:(新生代分配值/存活区最大利用值)*目标存活区利用率=(100M/10M)*80%=8次

 

  1. 垃圾收集数据

    新生代收集:ParNew29388次,用时:13m

    旧生代:ConurrentMarkSweep:0次,用时0s

     

    新生代平均每次收集暂停时间为:0.027s(平均每次用时:13m/29388=0.027s)。

    新生代收集29388次,旧生代0次:旧生代内存利用率远远低于新生代,能够适当放大旧生代,缩小新生代。

     

  2.  

     

    结论:扩大新生代内存,缩小旧生代内存,相应提高并发收集线程数量;增长-XX:MaxTenuringThreshold参数,设置值为8,要求对象在存活区之间Copy 10次在移动到旧生代。

     

 

  1. 并行垃圾收集自适应调整堆内存

     

**管控项目:64位windows服务器

jvm 64位: jdk1.5.0_16_b02

上线时间:2010.10,出现jvm不响应时间:2010.12.16

 

启动参数:

-server-Xss2M -XX:PermSize=64M -XX:MaxPermSize=64M

-XX:+UseParallelGC-XX:+UseAdaptiveSizePolicy -XX:+AggressiveHeap -XX:ParallelGCThreads=4

说明:采用并行垃圾回收器,堆内存经过JVM自适应调整(-XX:+UseAdaptiveSizePolicy-XX:+AggressiveHeap)。

 

问题:2010.12.16项目组发现运行在jvm上的引擎服务不响应,经分析是jvm在作垃圾全收集时,对jvm进行了一次自动重启。

方案:采用”并发收集器,内存参数固定”,手动执行垃圾收集后,不出现jvm重启现象。

 

  1. 采用并发收集,内存固定

**管控项目:64位windows服务器

jvm 64位: jdk1.5.0_16_b02

启动参数:

-server-Xss2M -XX:PermSize=64M -XX:MaxPermSize=64M -Xms2G -Xmx2G -Xmn512M

-XX:SurvivorRatio=16-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=10 -XX:ParallelGCThreads=4

 

分析:旧生代采用并发垃圾收集器(CMS)管理;新生代采用并行垃圾收集器(Parall);内存参数固定。

正常运行时间: 

1 hour 4 minutes

处理 CPU时间: 

6 minutes

JIT编译器: 

HotSpot 64-Bit Server Compiler

编译总时间: 

1 minute

 

垃圾收集器: 

Name = 'ParNew', Collections = 158, Total time spent = 9.392秒

垃圾收集器: 

Name = 'ConcurrentMarkSweep', Collections = 1, Total time spent = 2.076秒

 

14.   调优经验(摘抄)

 

14.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:MaxHeapFreeRatio=70  //GC后JVM堆空间向操做系统扩张的比率。

-XX:+AggressiveHeap            //用于JVM运行于大内存模式下,JVM的堆空间至少在1G以上,与-Xms、-Xmx不一样时使用,慎用!会致使JVM极度消/耗内存

 

在U-NICA这样的后台大型应用服务器系统来讲,咱们就采用了经过调整初始堆内存空间、堆增加量、增长新生代空间配置、使用并发收集算法、火车算法等方法来使的系统的垃圾收集能力得以优化。并且在具体实际测试过程当中也发现这些调整一般是有效并且成本低廉的。

 

14.2.  JIT调优参数的使用

从解释执行到即时编译,再到热点编译JVM走在一条不断优化的道路上,今天咱们经过一些简单的参数设置就能够得到之前梦想的性能,对于Java用户来讲,这的确是一条捷径:

-server                       //不少Hotspot的能力都是经过这个选项打开的,对于大型服务器尤其重要,这里能够启动热点编译功能

-Xmaxjitcodesize32m       //设置即时编译代码的最大尺寸

-Xint                           //纯解释执行,通常状况下不用它

-Xtime                        //不太清楚如何使用,总之是指定JIT的时间

-XX:+DisableExplicitGC          //是否屏蔽应用层的垃圾收集请求

-XX:-UseISM                    //使用大内存页模式则会减小GC的时间

-XX:-UseMPSS                //在使用ISM选项的同时不使用该选项,不然ISM无效

14.3.  Java线程调优参数的使用

-XX:-UseBoundThreads          //若是你的系统是Solaris8以上,尽情使用这个参数吧,操做系统内核的线程调度老是要必应用层的调度快一些

-XX:-UseLWPSynchronization//这个参数也是一样的,让操做系统来作线程同步这些工做

-XX:+UseThreadPriorities       //是否采用操做系统内部定义的线程优先级

-XX:CompileThreshold=10000//若是你想让你的系统更早变快一些,并且你的内存足够多的话,能够将这个参数值调小

-XX:PreBlockSpin=10             //仅仅用于Linux版本

-XX:ThreadStackSize=512     //设置线程栈的大小,若是你的应用中有比较大的循环或递归时使用。

-XX:+UseTLAB                //是否在线程的栈空间内分配对象,若是你的内存较大的话,而且配置了比较大的线程栈空间,则使用这个参数会使得临时&本地对象的申请和释放比较快。

相关文章
相关标签/搜索