高中化学,为什么P-P键能P小于0.05P-Cl键能?

了解JVM的垃圾收集器对于性能分析和调优很有帮助,一般系统挂死或出现性能问题,通过分析GC日志,往往可以为我们提供有用的线索。

Safepoint是java代码中一个线程可能暂停执行的一个位置,SafePoint保存了其他位置没有的一些运行信息。在这个位置上保存了线程上下文的任何信息,包括对象或者非对象的内部指针。在接收到JVM的进入Stop The World 的信息,在safepoint上,用户线程会被挂起。如果JNI代码想要访问在安全点上的用户线程,那么JNI所在线程也会阻塞直到用户线程离开安全点。因为在安全点上jvm线程信息被很好的描述,所以特别适合做一些全局性的操作,例如代码反优化,线程快照等等。

 在HotSpot虚拟机中,safepoint 协议是主动协作的 。每一个用户线程在安全点 上都会检测一个标志位,来决定自己是否暂停执行。 对于JIT编译后的代码,JIT会在代码特定的位置(通常来说,在方法的返回处和counted loop的结束处)上插入安全点代码。对于解释执行的代码,JVM会设置一个2字节的dispatch

  • 一个线程可以在SafePoint上,也可以不在SafePoint上。一个线程在SafePoint时,它的状态可以安全地其他JVM线程所操作和观测;不在SafePoint时,就不能。 

  • 当JVM决定达到一个全局的SafePoint(也叫做Stop the World),JVM里面所有的线程都要在SafePoint上并且不能离开,直到JVM让线程允许为止。这对要求所有线程都要被良好的描述的操作(比如CG,代码反优化等等)非常有好处。

  • 当你写一些非安全的代码的时候,你必须假设SafePoint有可能发生在任何两个字节码之间。

  • 非安全代码的调用并不要求必须有安全点,但是他们可以包含一个或者多个安全点。

  • 所有类型的JVM有一些效率非常高的技巧和去快速的穿过SafePoint,线程并不需要真正地进入SafePoint除非虚拟机指示线程这么做。

  • 所有的JNI方法都在SafePoint上执行。在安全点,JNI代码都不能改变和观测发起调用JNI代码线程的java机器状态。任何通过JNI API改变和观测调用线程的状态必须在调用线程离开安全点之后,以及再次进入SafePoint之前的时间内发生。

(1)标记:上面已经说到过,使用的就是可达性分析算法将无用的对象标记出来 

(2)将第一步标记的对象进行回收清除 

(1)效率问题:标记和清楚的效率都不高 

(2)空间问题:清除后会产生大量不连续的内存碎片。 

思想:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。

这种算法虽然实现简单,运行高效且不容易产生内存碎片,但是却对内存空间的使用做出了高昂的代价,因为能够使用的内存缩减到原来的一半。 

思想:在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。

内存被分为下面三个区域: 

(3)永久代:方法区 

新生代:包含有Enden、from survivor space、to survivor space三个区,绝大多数最新被创建的对象会被分配到这里,大部分对象在创建之后会变得很快不可达,对象从这个对象消失的过程称为”minor GC” 

特征:(1)GC的发生相对比较频繁 

(2)GC的发生比较迅速高效,因为新生代的空间通常比较小,并且可能包含了许多短周期对象。 

(3)经历过几次新生代的垃圾回收之后,存活下来的对象会被拷贝到老年代的堆空间中。 

老年代:从新生代存活下来的对象会被拷贝到这里,它的空间比新生代要大,所以在老年代上发生的GC要比新生代少得多。对象从老年代消失的过程称为”major GC”或者”full GC”。 

特征:(1)比新生代的堆空间要大 

(2)内存占用的增长比较慢 

(3)GC操作不是很频繁,但是耗时比新生代中的GC要长。

持久代:也被称为方法区,用来存放类常量和字符串常量,这个区域不是用来存储那些从老年代存活下来的对象。它也会发生GC操作。

内存分配与回收的几条策略 

3)、长期存活的对象将进入老年代 虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Enden出生并且经过第一次Minor GC仍然存活,并且能够被Survivor空间容纳,进入移动到Survivor空间,并且设置对象年龄为1,对象在Survivor区每熬过一个Minor GC,年龄就增加1岁,当它的年龄到达一定的程度(默认为15岁),就会被移动到老年代,这个年龄阀值可以通过-XX:MaxTenuringThreshold设置。 

4)、动态对象年龄判断 虚拟机并不是永远要求对象的年龄达到MaxTenuringThreshold才移动到老年代,如果Survivor区中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或者等于该年龄的对象也被移动到老年代。 

5)、空间分配担保 在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor

(1)新对象会被分配到Enden空间中。 

(2)当Enden空间满时,就会触发minor GC过程。

(3)没有被引用的对象就会被垃圾收集 

(4)被引用的对象会被复制到S0 survivor区,并且age加1。

当存活的对象达到了一个age的阀值,最终就会复制到老年代。 

(2)当存活的对象达到了一个age的阀值时,他们会被复制到老年代。 

在新生代中,每次垃圾收集时发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集,而老年代中因为对象存活率高,没有额外的空间对它进行分配担保,就必须使用”标记-清理”或者”标记-整理”算法进行回收。

(以下二、三部分图文内容来自于:)

2.并发垃圾收集和并行垃圾收集的区别

用户程序在继续运行,而垃圾收集程序线程运行于另一个CPU上。     

如CMS、G1(也有并行)。

因为Java对象大多是朝生夕灭,所以Minor GC非常频繁,一般回收速度也比较快; 

最基本、最悠久的收集器,他是一个单线程的收集器,而单线程是指当他在进行垃圾收集的时候,必须暂停其他所有的工作线程,直到它收集结束,被称为”Stop The World”。

优点:简单而高效(与其他收集器的单线程相比),对于限于单个CPU的环境,Serial收集器没有线程交互的开销,所以能获得最高的单线程收集效率。

适用:是HotSpot在Client模式下默认的新生代收集器;运行在Client模式下的虚拟机。

设置参数:"-XX:+UseSerialGC"添加该参数来显式的使用串行垃圾收集器。

ParNew垃圾收集器是Serial收集器的多线程版本。除了使用多条线程进行垃圾收集之外,其余的和Serial所有控制参数一样。在配置为CMS GC的情况下默认的新生代收集器,

优点:在多CPU的环境下可以发挥更高而效率,并且是唯一一个可以和CMS收集器搭配工作的新生代并行GC。

适用:运行在server模式下的虚拟机首选的新生代收集器。因为除Serial外,目前只有它能与CMS收集器配合工作; 在单个CPU环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销。

可以用"-XX:ParallelGCThreads”来限制垃圾收集的线程数,ParNew默认开启的收集线程与CPU的数量相同。

看上去和ParNew没什么区别(新生代收集器,采用复制算法,多线程收集),Parallel Scavenge收集器的特点是它的关注点在于达到一个可控制的CPU吞吐量,吞吐量=运行代码时间/(运行代码时间+垃圾收集时间)。较高的吞吐量可以最好的利用CPU的效率,即减少垃圾收集时间,让用户代码获得更长的运行时间。

优点:被称为”吞吐量优先”收集器,有一个自适应调节参数(-XX:+UseAdaptiveSizePolicy),当这个参数打开后,无需手动指定新生代大小(-Xmn)、Eden和Survivor比例(-XX:SurvivorRatio)、晋升老年代年龄限制(-XX:PretenureSizeThreshold)等细节参数,虚拟机会动态调节这些参数来提供最适合的停顿时间或最大吞吐量。适用:本身是Server级别多CPU机器上的默认GC方式,也可以通过-XX:+UseParallelGC来指定,并且可以采用-XX:ParallelGCThread来指定线程数。

设置参数:“-XX:MaxGCPauseMillis”配置最大垃圾收集停顿时间,“-XX:GCTimeRatio”配置吞吐量大小(值大于0小于100),即垃圾收集时间占总时间的比率。计算方法为:1/(1+n),默认值为99,即允许最大1%(1/(1+99))的垃圾收集时间。

其他参数:"-XX:+UseAdptiveSizePolicy”,开启这个参数后,不用手工指定一些细节参数,如:新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRation)、晋升老年代的对象年龄(-XX:PretenureSizeThreshold)等;JVM会根据当前系统运行情况收集性能监控信息,动态调整这些参数,以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC

Serial Old是Serial收集器的老年代版本,同样是一个单线程收集器,使用”标记-整理”算法。

适用:Client模式下虚拟机使用;在Server模式有两大用途:在JDK 1.5及以前的版本中与Parallel Scavenge收集器搭配使用;另一种用途作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。

其中初始标记、重新标记仍然是”Stop The World”,初始标记仅仅是标记一下GC Roots能直接关联的对象,并发标记进行GC Roots Tracing的过程,重新标记为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那部分对象,这个阶段停顿时间比初始标记阶段稍长一些,但比并发标记时间短。

优点:并发收集、低停顿。是HotSpot在JDK1.5推出的第一款真正意义上的并发收集器。第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。

适用:重视服务的响应速度、系统停顿时间和用户体验的互联网网站或者B/S系统。

CMS收集器3个明显的缺点:

1)对CPU资源非常敏感

总体来看,与Parallel Old垃圾收集器相比,CMS减少了执行老年代垃圾收集时应用暂停的时间;但却增加了新生代垃圾收集时应用暂停的时间、降低了吞吐量而且需要占用更大的堆空间。

G1(Garbage First)收集器是当前收集器技术最前沿成果,与之前的CMS相比有两个显著改进:基于”标记-整理”算法实现收集器和精确控制停顿。能够在基本不牺牲吞吐量的前提下完成低停顿的内存回收。

特点:1)并行与并发:能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(或CPU核心)来缩短"Stop The World”停顿的时间;可以通过并发的方式让垃圾收集与Java程序同时进行; 

2)分代收集:收集范围包括新生代和老年代,能独立管理整个GC堆(新生代和老年代),而不需要与其他收集器搭配;可以采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。3)空间整合:从整体看,G1是基于标记-整理算法,从局部(两个Region间)看,是基于复制算法, 这两种算法都不会产生内存碎片,收集后能提供规整的可用内存,有利于长时间运行。

4)可预测的停顿:低停顿的同时实现高吞吐量,G1除了追求低停顿处,还能建立可预测的停顿时间模型;可以明确指定M毫秒时间片内,垃圾收集消耗的时间不超过N毫秒;

应用场景:面向服务端应用,针对具有大内存、多处理器的机器;最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案;如:在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒;用来替换掉JDK1.5中的CMS收集器;       

在下面的情况时,使用G1可能比CMS好:1).超过50%的Java堆被活动数据占用;2).对象分配频率或年代提升频率变化很大;3).GC停顿时间过长(长于0.5至1秒)。

四、补充GC日志相关内容

监控GC在于判断JVM是否在良好高效地工作并且是否需要投入性能调优(主要包括应用程序优化与JVM参数优化),关注的数据大概有:

通过加入 -Xloggc:/home/XX/gc/app_gc.log 可以把GC输出至文件,这对长时间服务器GC监控很有帮助。以下列出一些参数大致打印的信息如下:

首先来说明一段在各个GC中通用的字段含义说明:

1)142826K->1K) 分别代表回收前、回收后以及总内存大小。

    CMS GC相对来说比较复杂,通过使用 -XX:+UseConcMarkSweepGC 参数在指定,但是一般情况需要更多的其他参数来保证它能比较好地达到我们的低延时目的,下面就部分常用参数做介绍:

GC 分析主要点在于:

注: jstack 命令可以查询当前应用线程状态,可用于判断是否存在死锁、线程等待原因等问题。

我要回帖

更多关于 p小于0.05 的文章

 

随机推荐