程序员人生 网站导航

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

栏目:综合技术时间:2016-06-06 08:00:55
本系列包括:
JVM性能调优1:JVM性能调优理论及实践(搜集整理)
JVM性能调优2:JVM性能调优参数整理
JVM性能调优3:JVM_堆溢出分析进程和命令
JVm性能调优4:GC日志分析
JVM性能调优5:Heap堆分析方法


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

1.      内存结构


1.1.     分代结构图


注意:


JVM中,非堆内存,根据模式不同分为不同的几个部份。


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


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


2.      性能指标


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


吞吐量throughput)指用来进行垃圾搜集以外工作所用的时间占总时间的百分比,1般要通太长时间的视察和丈量。吞吐量包括了分配内存所花费的时间在内(1般来讲无需对分配进行调优)。


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.) fromTuning 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). fromTuning GC with jdk 1.5


用户对垃圾搜集有不同的需求,例如,对Web服务器利用来讲,吞吐量是要侧重斟酌的,而暂停时间可能由于网络的反应时间而不那末明显;而对1个交互式图形界面的利用来讲,即便是短暂的暂停都会带来非常不好的用户体验。


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 .fromTuning GC with jdk 1.5


通常来讲,如何设置代的大小是在这些斟酌因素之间作出的1个权衡。例如,将新生代设置得很大会得到很好的吞吐性能,但是会增加暂停时间;反之,较小的新生代设置会减小暂停时间,但是下降了吞吐量。


1个代的大小不应当影响在其他代上进行垃圾搜集的频率和暂停时间。


3.      援用类型


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


3.1.     强援用


就是我们1般声明对象是时虚拟机生成的援用,强援用环境下,垃圾回收时需要严格判断当前对象是不是被强援用,如果被强援用,则不会被垃圾回收。


3.2.     软援用


软援用1般被做为缓存来使用。与强援用的区分是,软援用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是不是对软援用进行回收。如果剩余内存比较紧张,则虚拟机会回收软援用所援用的空间;如果剩余内存相对富裕,则不会进行回收。换句话说,虚拟机在产生OutOfMemory时,肯定是没有软援用存在的。


3.3.     弱援用


弱援用与软援用类似,都是作为缓存来使用。但与软援用不同,弱援用在进行垃圾回收时,是1定会被回收掉的,因此其生命周期只存在于1个垃圾回收周期内。


3.4.     虚援用


 


4.      内存分配回收次序


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


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


Eden的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对enden区进行垃圾回收,将enden区中的不再被其他对象所援用的对象进行烧毁(次搜集)。


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


再移动到养老区。


 



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


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


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


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


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


内存分配需要时间。


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


5.1.     援用计数法(ReferenceCounting


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


这类方法的好处是垃圾搜集较快,适用于实时环境。缺点是这类方法没法监测出循环援用。例如对象A援用对象B,对象B也援用对象A,则这两个对象可能没法被垃圾搜集器搜集。因此这类方法是垃圾搜集的初期策略,现在很少使用。


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


5.2.1.    基本思想


这类方法把每一个对象看做图中1个节点,对象之间的援用关系为图中各节点的邻接关系。垃圾搜集器从1个或数个根结点遍历对象图,如果有些对象节点永久没法到达,则这个对象可以被当作垃圾回收。


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


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

  2. 由基对象集内的对象动身,搜索所有可达的对象;

  3. 其余的不可达的对象,就是可以被回收的对象。

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


5.2.2.    GCRoots


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


《深入理解 Java 虚拟机:JVM高级特性与最好实践》1书中提到的 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”不1样,“1”中是 objects created by the classes loaded bysystem class loaders,这里是 theobjects, corresponding instances of system class loaders)、JVM内部的1些重要的异常类的对象、异常句柄的预分配对象和在类加载进程中自定义的类加载器。不幸的是,JVM其实不提供这些对象的任何额外的详细信息。因此这些实现相干的内容,需要依托分析来判定。


所以这个算法实行起来有两部份,第1部份就是到 JVM 的几个内存区域中找对象,第2部份就是应用图论算法


 


 


 


 


6.      垃圾回收算法


6.1.     标记-清除(Mark-Sweep



此算法履行分两阶段。第1阶段从援用根节点开始标记所有被援用的对象,第2阶段遍历全部堆,把未标记的对象清除。此算法需要暂停全部利用,同时,会产生内存碎片。


6.2.     标记-整理(Mark-Compact


此算法结合了标记-清除复制两个算法的优点。也是分两阶段,第1阶段从根节点开始标记所有被援用对象,第2阶段遍历全部堆,把清除未标记对象并且把存活对象紧缩到堆的其中1块,按顺序排放。此算法避免了标记-清除的碎片问题,同时也避免了复制算法的空间问题。


6.3.     复制(Copying


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


6.4.     增量搜集算法


增量搜集器把堆栈分为多个域,每次仅从1个域搜集垃圾。这会造成较小的利用程序中断。


6.5.     分代搜集算法


这类搜集器把堆栈分为两个或多个域,用以寄存不同寿命的对象。虚拟机生成的新对象1般放在其中的某个域中。过1段时间,继续存在的对象将取得使用期并转入更长寿命的域中。分代搜集器对不同的域使用不同的算法以优化性能。这样可以减少复制对象的时间。


6.6.     并发搜集算法


并发搜集器与利用程序同时运行。这些搜集器在某点上(比如紧缩时)1般都不能不停止其他操作以完成特定的任务,但是由于其他利用程序可进行其他的后台操作,所以中断其他处理的实际时间大大下降。


6.7.     并行搜集器


并行搜集器使用某种传统的算法并使用多线程并行的履行它们的工作。在多CPU机器上使用多线程技术可以显著的提高java利用程序的可扩大性。


6.8.     自适应搜集器


根据程序运行状态和堆的使用状态,自动选1种适合的垃圾回收算法。这样可以不局限与1种垃圾回收算法。


6.9.     火车增量算法


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

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐