转载html
url: http://blog.csdn.net/ning109314/article/details/10411495java
url:http://www.cnblogs.com/sunada2005/p/3577799.html程序员
url:http://www.open-open.com/lib/view/open1437834571349.html算法
url:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037056.htmlapache
url:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html数组
url:http://ifeve.com/jvm-internals/缓存
1. 什么是JVM?安全
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是经过在实际的计算机上仿真模拟各类计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操做系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就能够在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终仍是把字节码解释成具体平台上的机器指令执行。服务器
Java语言的一个很是重要的特色就是与平台的无关性。而使用Java虚拟机是实现这一特色的关键。通常的高级语言若是要在不一样的平台上运行,至少须要编译成不一样的目标代码。而引入Java语言虚拟机后,Java语言在不一样平台上运行时不须要从新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就能够在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的可以“一次编译,处处运行”的缘由。数据结构
2. JRE/JDK/JVM是什么关系?
3. JVM原理
7. JVM运行时数据区
vs.
vs.
vs.
上述贴图:都在说明JVM 理论中的内存模型
第一块:PC寄存器
PC寄存器是用于存储每一个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息。
第二块:JVM栈
JVM栈是线程私有的,每一个线程建立的同时都会建立JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。
第三块:堆(Heap)
它是JVM用来存储对象实例以及数组值的区域,能够认为Java中全部经过new建立的对象的内存都在此分配,Heap中的对象的内存须要等待GC进行回收。
(1) 堆是JVM中全部线程共享的,所以在其上进行对象内存的分配均须要进行加锁,这也致使了new对象的开销是比较大的
(2) Sun Hotspot JVM为了提高对象内存分配的效率,对于所建立的线程都会分配一块独立的空间TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行的状况计算而得,在TLAB上分配对象时不须要加锁,所以JVM在给线程的对象分配内存时会尽可能的在TLAB上分配,在这种状况下JVM中分配对象内存的性能和C基本是同样高效的,但若是对象过大的话则仍然是直接使用堆空间分配
(3) TLAB仅做用于新生代的Eden Space,所以在编写Java程序时,一般多个小的对象比大的对象分配起来更加高效。
(4) 全部新建立的Object 都将会存储在新生代Yong Generation中。若是Young Generation的数据在一次或屡次GC后存活下来,那么将被转移到OldGeneration。新的Object老是建立在Eden Space。
第四块:方法区域(Method Area)
(1)在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代。
(2)方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中经过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在必定的条件下它也会被GC,当方法区域须要使用的内存超过其容许的大小时,会抛出OutOfMemory的错误信息。
第五块:运行时常量池(Runtime Constant Pool)
存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。
第六块:本地方法堆栈(Native Method Stacks)
JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每一个native方法调用的状态。
8. JVM垃圾回收
GC (Garbage Collection)的基本原理:将内存中再也不被使用的对象进行回收,GC中用于回收的方法称为收集器,因为GC须要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽量的缩短GC对应用形成的暂停
(1)对新生代的对象的收集称为minor GC;
(2)对旧生代的对象的收集称为Full GC;
(3)程序中主动调用System.gc()强制执行的GC为Full GC。
不一样的对象引用类型, GC会采用不一样的方法进行回收,JVM对象的引用分为了四种类型:
(1)强引用:默认状况下,对象采用的均为强引用(这个对象的实例没有其余对象引用,GC时才会被回收)
(2)软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的状况下才会被GC)
(3)弱引用:在GC时必定会被GC回收
(4)虚引用:因为虚引用只是用来得知对象是否被GC
内存由 Perm 和 Heap 组成. 其中
Heap = {Old + NEW = { Eden , from, to } }
JVM内存模型中分两大块,一块是 NEW Generation, 另外一块是Old Generation. 在New Generation中,有一个叫Eden的空间,主要是用来存放新生的对象,还有两个Survivor Spaces(from,to), 它们用来存放每次垃圾回收后存活下来的对象。在Old Generation中,主要存放应用程序中生命周期长的内存对象,还有个Permanent Generation,主要用来放JVM本身的反射对象,好比类对象和方法对象等。
垃圾回收描述:
在New Generation块中,垃圾回收通常用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个Survivor Space, 当Survivor Space空间满了后, 剩下的live对象就被直接拷贝到Old Generation中去。所以,每次GC后,Eden内存块会被清空。在Old Generation块中,垃圾回收通常用mark-compact的算法,速度慢些,但减小内存要求.
垃圾回收分多级,0级为所有(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收NEW中的垃圾,内存溢出一般发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的状况。
当一个URL被访问时,内存申请过程以下:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。不然到下一步
C. JVM试图释放在Eden中全部不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区
D. Survivor区被用来做为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,不然会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行彻底的垃圾收集(0级)
F. 彻底垃圾收集后,若Survivor及OLD区仍然没法存放从Eden复制过来的部分对象,致使JVM没法在Eden区为新对象建立内存区域,则出现”out of memory错误”
JVM调优建议:
ms/mx:定义YOUNG+OLD段的总尺寸,ms为JVM启动时YOUNG+OLD的内存大小;mx为最大可占用的YOUNG+OLD内存大小。在用户生产环境上通常将这两个值设为相同,以减小运行期间系统在内存申请上所花的开销。
NewSize/MaxNewSize:定义YOUNG段的尺寸,NewSize为JVM启动时YOUNG的内存大小;MaxNewSize为最大可占用的YOUNG内存大小。在用户生产环境上通常将这两个值设为相同,以减小运行期间系统在内存申请上所花的开销。
PermSize/MaxPermSize:定义Perm段的尺寸,PermSize为JVM启动时Perm的内存大小;MaxPermSize为最大可占用的Perm内存大小。在用户生产环境上通常将这两个值设为相同,以减小运行期间系统在内存申请上所花的开销。
SurvivorRatio:设置Survivor空间和Eden空间的比例
内存溢出的可能性
1. OLD段溢出
这种内存溢出是最多见的状况之一,产生的缘由多是:
1) 设置的内存参数太小(ms/mx, NewSize/MaxNewSize)
2) 程序问题
单个程序持续进行消耗内存的处理,如循环几千次的字符串处理,对字符串处理应建议使用StringBuffer。此时不会报内存溢出错,却会使系统持续垃圾收集,没法处理其它请求,相关问题程序可经过Thread Dump获取(见系统问题诊断一章)单个程序所申请内存过大,有的程序会申请几十乃至几百兆内存,此时JVM也会因没法申请到资源而出现内存溢出,对此首先要找到相关功能,而后交予程序员修改,要找到相关程序,必须在Apache日志中寻找。
当Java对象使用完毕后,其所引用的对象却没有销毁,使得JVM认为他仍是活跃的对象而不进行回收,这样累计占用了大量内存而没法释放。因为目前市面上尚未对系统影响小的内存分析工具,故此时只能和程序员一块儿定位。
2. Perm段溢出
一般因为Perm段装载了大量的Servlet类而致使溢出,目前的解决办法:
1) 将PermSize扩大,通常256M可以知足要求
2) 若别无选择,则只能将servlet的路径加到CLASSPATH中,但通常不建议这么处理
3. C Heap溢出
系统对C Heap没有限制,故C Heap发生问题时,Java进程所占内存会持续增加,直到占用全部可用系统内存
其余:
JVM有2个GC线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区。Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,由于第二个线程被迫运行会下降JVM的性能。
为何一些程序频繁发生GC?有以下缘由:
l 程序内调用了System.gc()或Runtime.gc()。
l 一些中间件软件调用本身的GC方法,此时须要设置参数禁止这些GC。
l Java的Heap过小,通常默认的Heap值都很小。
l 频繁实例化对象,Release对象。此时尽可能保存并重用对象,例如使用StringBuffer()和String()。
若是你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java程序每次GC后最好能有65%的剩余空间。
经验之谈:
1.Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx的1/3[2]。
2.一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒以内完成[2]。
注意:
1.增长Heap的大小虽然会下降GC的频率,但也增长了每次GC的时间。而且GC运行时,全部的用户线程将暂停,也就是GC期间,Java应用程序不作任何工做。
2.Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,由于Java为其余任务分配内存,例如每一个线程的Stack等。
2.Stack的设定
每一个线程都有他本身的Stack。
-Xss
|
每一个线程的Stack大小
|
3.垃圾回收:
JVM中会在如下状况触发回收:对象没有被引用 , 做用域发生未捕捉异常 , 程序正常执行完毕 , 程序执行了System.exit() , 程序发生意外终止。 JVM中标记垃圾使用的算法是一种根搜索算法。简单的说,就是从一个叫GC Roots的对象开始 , 向下搜索 , 若是一个对象不能达到GC Roots对象的时候 , 说明它能够被回收了。这种算法比一种叫作引用计数法的垃圾标记算法要好,由于它避免了当两个对象啊互相引用时没法被回收的现象。
JVM中对于被标记为垃圾的对象进行回收时又分为了一下3种算法:
1.标记清除算法 ,该算法是从根集合扫描整个空间,标记存活的对象,而后在扫描整个空间对没有被标记的对象进行回收,这种算法在存活对象较多时比较高效,但会产生内存碎片。
2.复制算法 ,该算法是从根集合扫描,并将存活的对象复制到新的空间,这种算法在存活对象少时比较高效。
3.标记整理算法 ,标记整理算法和标记清除算法同样都会扫描并标记存活对象,在回收未标记对象的同时会整理被标记的对象,解决了内存碎片的问题。
JVM中,不一样的 内存区域做用和性质不同,使用的垃圾回收算法也不同,因此JVM中又定义了几种不一样的垃圾回收器(上图中连线表明两个回收器能够同时使用)
按照基本回收策略分
引用计数(Reference Counting):
比较古老的回收算法。原理是此对象有一个引用,即增长一个计数,删除一个引用则减小一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是没法处理循环引用的问题。
标记-清除(Mark-Sweep):
此算法执行分两阶段。第一阶段从引用根节点开始标记全部被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法须要暂停整个应用,同时,会产生内存碎片。
复制(Copying):
此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另一个区域中。算法每次只处理正在使用中的对象,所以复制成本比较小,同时复制过去之后还能进行相应的内存整理,不会出现“碎片”问题。固然,此算法的缺点也是很明显的,就是须要两倍内存空间。
标记-整理(Mark-Compact):
此算法结合了“标记-清除”和“复制”两个算法的优势。也是分两阶段,第一阶段从根节点开始标记全部被引用对象,第二阶段遍历整个堆,把清除未标记对象而且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。
增量收集(Incremental Collecting):实时垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么缘由JDK5.0中的收集器没有使用这种算法的。
分代收集(Generational Collecting):基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不一样生命周期的对象使用不一样的算法(上述方式中的一个)进行回收。如今的垃圾回收器(从J2SE1.2开始)都是使用此算法的。
按系统线程分
串行收集:串行收集使用单线程处理全部垃圾回收工做,由于无需多线程交互,实现容易,并且效率比较高。可是,其局限性也比较明显,即没法使用多处理器的优点,因此此收集适合单处理器机器。固然,此收集器也能够用在小数据量(100M左右)状况下的多处理器机器上。
并行收集:并行收集使用多线程处理垃圾回收工做,于是速度快,效率高。并且理论上CPU数目越多,越能体现出并行收集器的优点。(串型收集的并发版本,须要暂停jvm) 并行paralise指的是多个任务在多个cpu中一块儿并行执行,最后将结果合并。效率是N倍。
并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收工做时,须要暂停整个运行环境,而只有垃圾回收程序在运行,所以,系统在垃圾回收时会有明显的暂停,并且暂停时间会由于堆越大而越长。(和并行收集不一样,并发只有在开头和结尾会暂停jvm)并发concurrent指的是多个任务在一个cpu伪同步执行,但实际上是串行调度的,效率并不是直接是N倍。
分代垃圾回收
分代的垃圾回收策略,是基于这样一个事实:不一样的对象的生命周期是不同的。所以,不一样生命周期的对象能够采起不一样的收集方式,以便提升回收效率。
在Java程序运行的过程当中,会产生大量的对象,其中有些对象是与业务信息相关,好比Http请求中的Session对象、线程、Socket链接,这类对象跟业务直接挂钩,所以生命周期比较长。可是还有一些对象,主要是程序运行过程当中生成的临时变量,这些对象生命周期会比较短,好比:String对象,因为其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次便可回收。
试想,在不进行对象存活时间区分的状况下,每次垃圾回收都是对整个堆空间进行回收,花费时间相对会长,同时,由于每次回收都须要遍历全部存活对象,但实际上,对于生命周期长的对象而言,这种遍历是没有效果的,由于可能进行了不少次遍历,可是他们依旧存在。所以,分代垃圾回收采用分治的思想,进行代的划分,把不一样生命周期的对象放在不一样代上,不一样代上采用最适合它的垃圾回收方式进行回收。
如图所示:
虚拟机中的共划分为三个代:年轻代(Young Generation)、年老点(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。
年轻代:
全部新生成的对象首先都是放在年轻代的。年轻代的目标就是尽量快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(通常而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的而且此时还存活的对象,将被复制“年老区(Tenured)”。须要注意,Survivor的两个区是对称的,没前后关系,因此同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。并且,Survivor区总有一个是空的。同时,根据程序须要,Survivor区是能够配置为多个的(多于两个),这样能够增长对象在年轻代中的存在时间,减小被放到年老代的可能。
年老代:
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。所以,能够认为年老代中存放的都是一些生命周期较长的对象。
持久代:
用于存放静态文件,现在Java类、方法等。持久代对垃圾回收没有显著影响,可是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候须要设置一个比较大的持久代空间来存放这些运行过程当中新增的类。持久代大小经过-XX:MaxPermSize=<N>进行设置。
什么状况下触发垃圾回收
因为对象进行了分代处理,所以垃圾回收区域、时间也不同。GC有两种类型:Scavenge GC和Full GC。
Scavenge GC
通常状况下,当新对象生成,而且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,而且把尚且存活的对象移动到Survivor区。而后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。由于大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,因此Eden区的GC会频繁进行。于是,通常在这里须要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
Full GC
对整个堆进行整理,包括Young、Tenured和Perm。Full GC由于须要对整个对进行回收,因此比Scavenge GC要慢,所以应该尽量减小Full GC的次数。在对JVM调优的过程当中,很大一部分工做就是对于FullGC的调节。有以下缘由可能致使Full GC:
· 年老代(Tenured)被写满
· 持久代(Perm)被写满
· System.gc()被显示调用
·上一次GC以后Heap的各域分配策略动态变化
图1 | --> 图2 | --> 图3 | --> 图4 | -->
图1 --> 图2 --> 图3 --> 图4 -->
1.Serial GC 。从名字上看,串行GC意味着是一种单线程的,因此它要求收集的时候全部的线程暂停。这对于高性能的应用是不合理的,因此串行GC通常用于Client模式的JVM中。2.ParNew GC 。是在SerialGC的基础上,增长了多线程机制。可是若是机器是单CPU的,这种收集器是比SerialGC效率低的。
3.Parrallel Scavenge GC 。这种收集器又叫吞吐量优先收集器,而吞吐量=程序运行时间/(JVM执行回收的时间+程序运行时间),假设程序运行了100分钟,JVM的垃圾回收占用 1分钟,那么吞吐量就是99%。Parallel Scavenge GC因为能够提供比较不错的吞吐量,因此被做为了server模式JVM的默认配置。
4.ParallelOld 是老生代并行收集器的一种,使用了标记整理算法,是JDK1.6中引进的,在以前 老生代 只能使用串行回收收集器。
5.Serial Old 是老生代client模式下的默认收集器,单线程执行,同时也做为CMS收集器失败后的备用收集器。
6.CMS 又称响应时间优先回收器,使用标记清除算法。他的回收线程数为(CPU核心数+3)/4,因此当CPU核心数为2时比较高效些。CMS分为4个过程:初始标记、并发标记、从新标记、并发清除。
7.GarbageFirst(G1) 。比较特殊的是G1回收器既能够回收Young Generation,也能够回收Tenured Generation。它是在JDK6的某个版本中才引入的,性能比较高,同时注意了吞吐量和响应时间。
对于垃圾收集器的组合使用能够经过下表中的参数指定:
默认的GC种类能够经过jvm.cfg或者经过jmap dump出heap来查看,通常咱们经过jstat -gcutil [pid] 1000能够查看每秒gc的大致状况,或者能够在启动参数中加入:-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log来记录GC日志。
GC中有一种状况叫作Full GC,如下几种状况会触发Full GC:
1.Tenured Space空间不足以建立打的对象或者数组,会执行FullGC,而且当FullGC以后空间若是还不够,那么会OOM:java heap space。
2.Permanet Generation的大小不足,存放了太多的类信息,在非CMS状况下回触发FullGC。若是以后空间还不够,会OOM:PermGen space。
3.CMS GC时出现promotion failed和concurrent mode failure时,也会触发FullGC。
promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下形成的;
concurrent mode failure是在执行CMS GC的过程当中同时有对象要放入旧生代,而此时旧生代空间不足形成的。
4.判断MinorGC后,要晋升到TenuredSpace的对象大小大于TenuredSpace的大小,也会触发FullGC。能够看出,当FullGC频繁发生时,必定是内存出问题了。
young generation有eden、2个survivor 区域组成。其中一个survivor区域一直是空的,是eden区域和另外一个survivor区域在下一次copy collection后活着的objecy的目的地。object在survivo区域被复制直到转移到tenured区。
咱们要尽可能减小 Full gc 的次数(tenured generation 通常比较大,收集的时间较长,频繁的Full gc会致使应用的性能收到严重的影响)。
堆内存GC
JVM(采用分代回收的策略),用较高的频率对年轻的对象(young generation)进行YGC,而对老对象(tenured generation)较少(tenured generation 满了后才进行)进行Full GC。这样就不须要每次GC都将内存中全部对象都检查一遍。
非堆内存不GC
GC不会在主程序运行期对PermGen Space进行清理,因此若是你的应用中有不少CLASS(特别是动态生成类,固然permgen space存放的内容不只限于类)的话,就极可能出现PermGen Space错误。
内存申请、对象衰老过程
1、内存申请过程
GC性能方面的考虑
对于GC的性能主要有2个方面的指标:吞吐量throughput(工做时间不算gc的时间占总的时间比)和暂停pause(gc发生时app对外显示的没法响应)。
1. Total Heap
默认状况下,vm会增长/减小heap大小以维持free space在整个vm中占的比例,这个比例由MinHeapFreeRatio和MaxHeapFreeRatio指定。
通常而言,server端的app会有如下规则:
2. The Young Generation
另一个对于app流畅性运行影响的因素是young generation的大小。young generation越大,minor collection越少;可是在固定heap size状况下,更大的young generation就意味着小的tenured generation,就意味着更多的major collection(major collection会引起minor collection)。
NewRatio反映的是young和tenured generation的大小比例。NewSize和MaxNewSize反映的是young generation大小的下限和上限,将这两个值设为同样就固定了young generation的大小(同Xms和Xmx设为同样)。
若是但愿,SurvivorRatio也能够优化survivor的大小,不过这对于性能的影响不是很大。SurvivorRatio是eden和survior大小比例。
通常而言,server端的app会有如下规则:
经验&&规则
promotion failed:
垃圾回收时promotion failed是个很头痛的问题,通常多是两种缘由产生,第一个缘由是救助空间不够,救助空间里的对象还不该该被移动到年老代,但年轻代又有不少对象须要放入救助空间;第二个缘由是年老代没有足够的空间接纳来自年轻代的对象;这两种状况都会转向Full GC,网站停顿时间较长。
解决方方案一:
第一个缘由个人最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0便可,第二个缘由个人解决办法是设置CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。
解决方案一的改进方案:
又有改进了,上面方法不太好,由于没有用到救助空间,因此年老代容易满,CMS执行会比较频繁。我改善了一下,仍是用救助空间,可是把救助空间加大,这样也不会有promotion failed。具体操做上,32位Linux和64位Linux好像不同,64位系统彷佛只要配置MaxTenuringThreshold参数,CMS仍是有暂停。为了解决暂停问题和promotion failed问题,最后我设置-XX:SurvivorRatio=1 ,并把MaxTenuringThreshold去掉,这样即没有暂停又不会有promotoin failed,并且更重要的是,年老代和永久代上升很是慢(由于好多对象到不了年老代就被回收了),因此CMS执行频率很是低,好几个小时才执行一次,这样,服务器都不用重启了。
JVM参数的含义 实例见实例分析
参数名称 | 含义 | 默认值 | |
-Xms | 初始堆大小 | 物理内存的1/64(<1GB) | 默认(MinHeapFreeRatio参数能够调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制. |
-Xmx | 最大堆大小 | 物理内存的1/4(<1GB) | 默认(MaxHeapFreeRatio参数能够调整)空余堆内存大于70%时,JVM会减小堆直到 -Xms的最小限制 |
-Xmn | 年轻代大小(1.4or lator) | 注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不一样的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小. 增大年轻代后,将会减少年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 |
|
-XX:NewSize | 设置年轻代大小(for 1.3/1.4) | ||
-XX:MaxNewSize | 年轻代最大值(for 1.3/1.4) | ||
-XX:PermSize | 设置持久代(perm gen)初始值 | 物理内存的1/64 | |
-XX:MaxPermSize | 设置持久代最大值 | 物理内存的1/4 | |
-Xss | 每一个线程的堆栈大小 | JDK5.0之后每一个线程堆栈大小为1M,之前每一个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减少这个值能生成更多的线程.可是操做系统对一个进程内的线程数仍是有限制的,不能无限生成,经验值在3000~5000左右 通常小的应用, 若是栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,须要严格的测试。(校长) 和threadstacksize选项解释很相似,官方文档彷佛没有解释,在论坛中有这样一句话:"” -Xss is translated in a VM flag named ThreadStackSize” 通常设置这个值就能够了。 |
|
-XX:ThreadStackSize | Thread Stack Size | (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.] | |
-XX:NewRatio | 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) | -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 Xms=Xmx而且设置了Xmn的状况下,该参数不须要进行设置。 |
|
-XX:SurvivorRatio | Eden区与Survivor区的大小比值 | 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 | |
-XX:LargePageSizeInBytes | 内存页的大小不可设置过大, 会影响Perm的大小 | =128m | |
-XX:+UseFastAccessorMethods | 原始类型的快速优化 | ||
-XX:+DisableExplicitGC | 关闭System.gc() | 这个参数须要严格的测试 | |
-XX:MaxTenuringThreshold | 垃圾最大年龄 | 若是设置为0的话,则年轻代对象不通过Survivor区,直接进入年老代. 对于年老代比较多的应用,能够提升效率.若是将此值设置为一个较大值,则年轻代对象会在Survivor区进行屡次复制,这样能够增长对象再年轻代的存活 时间,增长在年轻代即被回收的几率 该参数只有在串行GC时才有效. |
|
-XX:+AggressiveOpts | 加快编译 | ||
-XX:+UseBiasedLocking | 锁机制的性能改善 | ||
-Xnoclassgc | 禁用垃圾回收 | ||
-XX:SoftRefLRUPolicyMSPerMB | 每兆堆空闲空间中SoftReference的存活时间 | 1s | softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap |
-XX:PretenureSizeThreshold | 对象超过多大是直接在旧生代分配 | 0 | 单位字节 新生代采用Parallel Scavenge GC时无效 另外一种直接在旧生代分配的状况是大的数组对象,且数组中无外部引用对象. |
-XX:TLABWasteTargetPercent | TLAB占eden区的百分比 | 1% | |
-XX:+CollectGen0First | FullGC时是否先YGC | false |
并行收集器相关参数
-XX:+UseParallelGC | Full GC采用parallel MSC (此项待验证) |
选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证) |
|
-XX:+UseParNewGC | 设置年轻代为并行收集 | 可与CMS收集同时使用 JDK5.0以上,JVM会根据系统配置自行设置,因此无需再设置此值 |
|
-XX:ParallelGCThreads | 并行收集器的线程数 | 此值最好配置与处理器数目相等 一样适用于CMS | |
-XX:+UseParallelOldGC | 年老代垃圾收集方式为并行收集(Parallel Compacting) | 这个是JAVA 6出现的参数选项 | |
-XX:MaxGCPauseMillis | 每次年轻代垃圾回收的最长时间(最大暂停时间) | 若是没法知足此时间,JVM会自动调全年轻代大小,以知足此值. | |
-XX:+UseAdaptiveSizePolicy | 自动选择年轻代区大小和相应的Survivor区比例 | 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开. | |
-XX:GCTimeRatio | 设置垃圾回收时间占程序运行时间的百分比 | 公式为1/(1+n) | |
-XX:+ScavengeBeforeFullGC | Full GC前调用YGC | true | Do young generation GC prior to a full GC. (Introduced in 1.4.1.) |
CMS相关参数
-XX:+UseConcMarkSweepGC | 使用CMS内存收集 | 测试中配置这个之后,-XX:NewRatio=4的配置失效了,缘由不明.因此,此时年轻代大小最好用-Xmn设置.??? | |
-XX:+AggressiveHeap | 试图是使用大量的物理内存 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量) 至少须要256MB内存 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提高) |
||
-XX:CMSFullGCsBeforeCompaction | 多少次后进行内存压缩 | 因为并发收集器不对内存空间进行压缩,整理,因此运行一段时间之后会产生"碎片",使得运行效率下降.此值设置运行多少次GC之后对内存空间进行压缩,整理. | |
-XX:+CMSParallelRemarkEnabled | 下降标记停顿 | ||
-XX+UseCMSCompactAtFullCollection | 在FULL GC的时候, 对年老代的压缩 | CMS是不会移动内存的, 所以, 这个很是容易产生碎片, 致使内存不够用, 所以, 内存的压缩这个时候就会被启用。 增长这个参数是个好习惯。 可能会影响性能,可是能够消除碎片 |
|
-XX:+UseCMSInitiatingOccupancyOnly | 使用手动定义初始化定义开始CMS收集 | 禁止hostspot自行触发CMS GC | |
-XX:CMSInitiatingOccupancyFraction=70 | 使用cms做为垃圾回收 使用70%后开始CMS收集 |
92 | 为了保证不出现promotion failed(见下面介绍)错误,该值的设置须要知足如下公式CMSInitiatingOccupancyFraction计算公式 |
-XX:CMSInitiatingPermOccupancyFraction | 设置Perm Gen使用到达多少比率时触发 | 92 | |
-XX:+CMSIncrementalMode | 设置为增量模式 | 用于单CPU状况 | |
-XX:+CMSClassUnloadingEnabled |
辅助信息
-XX:+PrintGC | 输出形式: [GC 118250K->113543K(130112K), 0.0094143 secs] |
||
-XX:+PrintGCDetails | 输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] |
||
-XX:+PrintGCTimeStamps | |||
-XX:+PrintGC:PrintGCTimeStamps | 可与-XX:+PrintGC -XX:+PrintGCDetails混合使用 输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs] |
||
-XX:+PrintGCApplicationStoppedTime | 打印垃圾回收期间程序暂停的时间.可与上面混合使用 | 输出形式:Total time for which application threads were stopped: 0.0468229 seconds | |
-XX:+PrintGCApplicationConcurrentTime | 打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用 | 输出形式:Application time: 0.5291524 seconds | |
-XX:+PrintHeapAtGC | 打印GC先后的详细堆栈信息 | ||
-Xloggc:filename | 把相关日志信息记录到文件以便分析. 与上面几个配合使用 |
||
-XX:+PrintClassHistogram |
garbage collects before printing the histogram. | ||
-XX:+PrintTLAB | 查看TLAB空间的使用状况 | ||
XX:+PrintTenuringDistribution | 查看每次minor GC后新的存活周期的阈值 | Desired survivor size 1048576 bytes, new threshold 7 (max 15) |
GC
传说中的G1,传说中的low-pause垃圾收集。Java SE 6的update14版本中已经包含测试版,能够在启动时加JVM参数来启用
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
http://www.blogjava.net/BlueDavy/archive/2009/03/11/259230.html
本文摘自《构建高性能的大型分布式Java应用》一书,Garbage First简称G1,它的目标是要作到尽可能减小GC所致使的应用暂停的时间,让应用达到准实时的效果,同时保持JVM堆空间的利用率,将做为CMS的替代者在JDK 7中闪亮登场,其最大的特点在于容许指定在某个时间段内GC所致使的应用暂停的时间最大为多少,例如在100秒内最多容许GC致使的应用暂停时间为1秒,这个特性对于准实时响应的系统而言很是的吸引人,这样就不再用担忧系统忽然会暂停个两三秒了。
G1要作到这样的效果,也是有前提的,一方面是硬件环境的要求,必须是多核的CPU以及较大的内存(从规范来看,512M以上就知足条件了),另一方面是须要接受吞吐量的稍微下降,对于实时性要求高的系统而言,这点应该是能够接受的。
为了可以达到这样的效果,G1在原有的各类GC策略上进行了吸取和改进,在G1中能够看到增量收集器和CMS的影子,但它不只仅是吸取原有GC策略的优势,并在此基础上作出了不少的改进,简单来讲,G1吸取了增量GC以及CMS的精髓,将整个jvm Heap划分为多个固定大小的region,扫描时采用Snapshot-at-the-beginning的并发marking算法(具体在后面内容详细解释)对整个heap中的region进行mark,回收时根据region中活跃对象的bytes进行排序,首先回收活跃对象bytes小以及回收耗时短(预估出来的时间)的region,回收的方法为将此region中的活跃对象复制到另外的region中,根据指定的GC所能占用的时间来估算能回收多少region,这点和之前版本的Full GC时得处理整个heap很是不一样,这样就作到了可以尽可能短期的暂停应用,又能回收内存,因为这种策略在回收时首先回收的是垃圾对象所占空间最多的region,所以称为Garbage First。
看完上面对于G1策略的简短描述,并不能清楚的掌握G1,在继续详细看G1的步骤以前,必须先明白G1对于JVM Heap的改造,这些对于习惯了划分为new generation、old generation的你们来讲都有很多的新意。
G1将Heap划分为多个固定大小的region,这也是G1可以实现控制GC致使的应用暂停时间的前提,region之间的对象引用经过remembered set来维护,每一个region都有一个remembered set,remembered set中包含了引用当前region中对象的region的对象的pointer,因为同时应用也会形成这些region中对象的引用关系不断的发生改变,G1采用了Card Table来用于应用通知region修改remembered sets,Card Table由多个512字节的Card构成,这些Card在Card Table中以1个字节来标识,每一个应用的线程都有一个关联的remembered set log,用于缓存和顺序化线程运行时形成的对于card的修改,另外,还有一个全局的filled RS buffers,当应用线程执行时修改了card后,若是形成的改变仅为同一region中的对象之间的关联,则不记录remembered set log,如形成的改变为跨region中的对象的关联,则记录到线程的remembered set log,如线程的remembered set log满了,则放入全局的filled RS buffers中,线程自身则从新建立一个新的remembered set log,remembered set自己也是一个由一堆cards构成的哈希表。
尽管G1将Heap划分为了多个region,但其默认采用的仍然是分代的方式,只是仅简单的划分为了年轻代(young)和非年轻代,这也是因为G1仍然坚信大多数新建立的对象都是不须要长的生命周期的,对于应用新建立的对象,G1将其放入标识为young的region中,对于这些region,并不记录remembered set logs,扫描时只需扫描活跃的对象,G1在分代的方式上还可更细的划分为:fully young或partially young,fully young方式暂停的时候仅处理young regions,partially一样处理全部的young regions,但它还会根据容许的GC的暂停时间来决定是否要加入其余的非young regions,G1是运行到fully-young方式仍是partially young方式,外部是不能决定的,在启动时,G1采用的为fully-young方式,当G1完成一次Concurrent Marking后,则切换为partially young方式,随后G1跟踪每次回收的效率,若是回收fully-young中的regions已经能够知足内存须要的话,那么就切换回fully young方式,但当heap size的大小接近满的状况下,G1会切换到partially young方式,以保证能提供足够的内存空间给应用使用。
除了分代方式的划分外,G1还支持另一种pure G1的方式,也就是不进行代的划分,pure方式和分代方式的具体不一样在下面的具体执行步骤中进行描述。
掌握了这些概念后,继续来看G1的具体执行步骤:
1. Initial Marking
G1对于每一个region都保存了两个标识用的bitmap,一个为previous marking bitmap,一个为next marking bitmap,bitmap中包含了一个bit的地址信息来指向对象的起始点。
开始Initial Marking以前,首先并发的清空next marking bitmap,而后中止全部应用线程,并扫描标识出每一个region中root可直接访问到的对象,将region中top的值放入next top at mark start(TAMS)中,以后恢复全部应用线程。
触发这个步骤执行的条件为:
l G1定义了一个JVM Heap大小的百分比的阀值,称为h,另外还有一个H,H的值为(1-h)*Heap Size,目前这个h的值是固定的,后续G1也许会将其改成动态的,根据jvm的运行状况来动态的调整,在分代方式下,G1还定义了一个u以及soft limit,soft limit的值为H-u*Heap Size,当Heap中使用的内存超过了soft limit值时,就会在一次clean up执行完毕后在应用容许的GC暂停时间范围内尽快的执行此步骤;
l 在pure方式下,G1将marking与clean up组成一个环,以便clean up能充分的使用marking的信息,当clean up开始回收时,首先回收可以带来最多内存空间的regions,当通过屡次的clean up,回收到没多少空间的regions时,G1从新初始化一个新的marking与clean up构成的环。
2. Concurrent Marking
按照以前Initial Marking扫描到的对象进行遍历,以识别这些对象的下层对象的活跃状态,对于在此期间应用线程并发修改的对象的以来关系则记录到remembered set logs中,新建立的对象则放入比top值更高的地址区间中,这些新建立的对象默认状态即为活跃的,同时修改top值。
3. Final Marking Pause
当应用线程的remembered set logs未满时,是不会放入filled RS buffers中的,在这样的状况下,这些remebered set logs中记录的card的修改就会被更新了,所以须要这一步,这一步要作的就是把应用线程中存在的remembered set logs的内容进行处理,并相应的修改remembered sets,这一步须要暂停应用,并行的运行。
4. Live Data Counting and Cleanup
值得注意的是,在G1中,并非说Final Marking Pause执行完了,就确定执行Cleanup这步的,因为这步须要暂停应用,G1为了可以达到准实时的要求,须要根据用户指定的最大的GC形成的暂停时间来合理的规划何时执行Cleanup,另外还有几种状况也是会触发这个步骤的执行的:
l G1采用的是复制方法来进行收集,必须保证每次的”to space”的空间都是够的,所以G1采起的策略是当已经使用的内存空间达到了H时,就执行Cleanup这个步骤;
l 对于full-young和partially-young的分代模式的G1而言,则还有状况会触发Cleanup的执行,full-young模式下,G1根据应用可接受的暂停时间、回收young regions须要消耗的时间来估算出一个yound regions的数量值,当JVM中分配对象的young regions的数量达到此值时,Cleanup就会执行;partially-young模式下,则会尽可能频繁的在应用可接受的暂停时间范围内执行Cleanup,并最大限度的去执行non-young regions的Cleanup。
这一步中GC线程并行的扫描全部region,计算每一个region中低于next TAMS值中marked data的大小,而后根据应用所指望的GC的短延时以及G1对于region回收所需的耗时的预估,排序region,将其中活跃的对象复制到其余region中。
G1为了可以尽可能的作到准实时的响应,例如估算暂停时间的算法、对于常常被引用的对象的特殊处理等,G1为了可以让GC既可以充分的回收内存,又可以尽可能少的致使应用的暂停,可谓费尽心思,从G1的论文中的性能评测来看效果也是不错的,不过若是G1能容许开发人员在编写代码时指定哪些对象是不用mark的就更完美了,这对于有巨大缓存的应用而言,会有很大的帮助,G1将随JDK 6 Update 14 beta发布。
http://www.iteye.com/topic/1119491
1.整体介绍:
CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来得到最短回收停顿时间的垃圾回收器。并发意味着除了开头和结束阶段,须要暂停JVM,其它时间gc和应用一块儿执行。对于要求服务器响应速度的应用上,这种垃圾回收器很是适合。在启动JVM参数加上-XX:+UseConcMarkSweepGC ,这个参数表示对于老年代的回收采用CMS。CMS采用的基础算法是:标记—清除。默认会开启 -XX :+UseParNewGC,在年轻代使用并行复制收集。
2.CMS过程:
初始标记 :在这个阶段,须要虚拟机停顿正在执行的任务,官方的叫法STW(Stop The Word)。这个过程从垃圾回收的"根对象"开始,只扫描到可以和"根对象"直接关联的对象,并做标记。因此这个过程虽然暂停了整个JVM,可是很快就完成了。
并发标记 :这个阶段紧随初始标记阶段,在初始标记的基础上继续向下追溯标记。并发标记阶段,应用程序的线程和并发标记的线程并发执行,因此用户不会感觉到停顿。
并发预清理 :并发预清理阶段仍然是并发的。在这个阶段,虚拟机查找在执行并发标记阶段新进入老年代的对象(可能会有一些对象重新生代晋升到老年代, 或者有一些对象被分配到老年代)。经过从新扫描,减小下一个阶段"从新标记"的工做,由于下一个阶段会Stop The World。
从新标记 :这个阶段会暂停虚拟机,收集器线程扫描在CMS堆中剩余的对象。扫描从"跟对象"开始向下追溯,并处理对象关联。
并发清理 :清理垃圾对象,这个阶段收集器线程和应用程序线程并发执行。
并发重置 :这个阶段,重置CMS收集器的数据结构,等待下一次垃圾回收。
CSM执行过程:
3.CMS缺点
总得来讲,CMS回收器减小了回收的停顿时间,可是下降了堆空间的利用率。
4.啥时候用CMS
若是你的应用程序对停顿比较敏感,而且在应用程序运行的时候能够提供更大的内存和更多的CPU(也就是硬件牛逼),那么使用CMS来收集会给你带来好处。还有,若是在JVM中,有相对较多存活时间较长的对象(老年代比较大)会更适合使用CMS。
jmap
jmap -heap pid (不能观察G1模式)
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 268435456 (256.0MB)
MaxNewSize = 268435456 (256.0MB)
OldSize = 805306368 (768.0MB)
NewRatio = 7
SurvivorRatio = 8
PermSize = 134217728 (128.0MB)
MaxPermSize = 134217728 (128.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 241631232 (230.4375MB)
used = 145793088 (139.03912353515625MB)
free = 95838144 (91.39837646484375MB)
60.33702133340114% used
Eden Space:
capacity = 214827008 (204.875MB)
used = 132689456 (126.54252624511719MB)
free = 82137552 (78.33247375488281MB)
61.7657236095752% used
From Space:
capacity = 26804224 (25.5625MB)
used = 13103632 (12.496597290039062MB)
free = 13700592 (13.065902709960938MB)
48.886444166411984% used
To Space:
capacity = 26804224 (25.5625MB)
used = 0 (0.0MB)
free = 26804224 (25.5625MB)
0.0% used
concurrent mark-sweep generation: (old区)
capacity = 1879048192 (1792.0MB)
used = 1360638440 (1297.6059341430664MB)
free = 518409752 (494.3940658569336MB)
72.41104543209076% used
Perm Generation:
capacity = 134217728 (128.0MB)
used = 65435064 (62.40373992919922MB)
free = 68782664 (65.59626007080078MB)
48.75292181968689% used
jmap -histo:live pid
num #instances #bytes class name
----------------------------------------------
1: 3148147 209172848 [B
2: 2584345 144723320 java.lang.ref.SoftReference
3: 2578827 123783696 sun.misc.CacheEntry
4: 781560 112544640 com.sun.net.ssl.internal.ssl.SSLSessionImpl
5: 1385200 89970592 [C
6: 783287 87807200 [Ljava.util.Hashtable$Entry;
7: 1421399 56855960 java.lang.String
8: 12 56828880 [Lsun.misc.CacheEntry;
9: 2343358 56240592 com.sun.net.ssl.internal.ssl.SessionId
10: 783185 50123840 java.util.Hashtable
11: 783094 50118016 java.lang.ref.Finalizer
12: 287243 36086720 [Ljava.lang.Object;
13: 263376 33712128 org.apache.commons.pool.impl.GenericObjectPool
jstat
jstat -gccause 31169 60000 1000
(sweep 1,2) (Eden) (Old) (Perm) (Young GC, GCTime)(Full GC, GCTime)
S0 S1 E O P YGC YGCT FGC FGCT GCT LGCC GCC
48.80 0.00 68.94 69.55 48.86 30202 725.319 51835 5083.298 5808.616 unknown GCCause No GC
47.98 0.00 37.47 69.61 48.86 30206 725.385 51835 5083.298 5808.682 unknown GCCause No GC
50.73 0.00 51.72 69.65 48.86 30210 725.459 51835 5083.298 5808.757 unknown GCCause No GC
0.00 50.02 82.67 69.60 48.84 30213 725.508 51836 5091.572 5817.081 unknown GCCause No GC
jstat -gcutil $pid
S0 S1 E O P YGC YGCT FGC FGCT GCT
74.79 0.00 95.15 0.86 37.35 2 0.112 0 0.000 0.112
O = old occupied
YGC = young gc time ( new part )
YGCT = young gc total cost time
FGC = full gc time ( old part )
FGCT = full gc total cost time
GCT = all gc cost time
jvisualvm
window下启动远程监控,并在被监控服务端,启动jstatd服务。
建立安全策略文件,并命名为jstatd.all.policy
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
jstatd -J-Djava.security.policy=jstatd.all.policy -p 8080 &
-server -Xmx2g -Xms2g -Xmn512m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true
The (original) copying collector (Enabled by default). When this collector kicks in, all application threads are stopped, and the copying collection proceeds using one thread (which means only one CPU even if on a multi-CPU machine). This is known as a stop-the-world collection, because basically the JVM pauses everything else until the collection is completed.
The parallel copying collector (Enabled using -XX:+UseParNewGC). Like the original copying collector, this is a stop-the-world collector. However this collector parallelizes the copying collection over multiple threads, which is more efficient than the original single-thread copying collector for multi-CPU machines (though not for single-CPU machines). This algorithm potentially speeds up young generation collection by a factor equal to the number of CPUs available, when compared to the original singly-threaded copying collector.
The parallel scavenge collector (Enabled using -XX:UseParallelGC). This is like the previous parallel copying collector, but the algorithm is tuned for gigabyte heaps (over 10GB) on multi-CPU machines. This collection algorithm is designed to maximize throughput while minimizing pauses. It has an optional adaptive tuning policy which will automatically resize heap spaces. If you use this collector, you can only use the the original mark-sweep collector in the old generation (i.e. the newer old generation concurrent collector cannot work with this young generation collector).
UserParallelGC使用了更高效的算法,用于处理大规模内存>10G场景,提供了大吞吐量功能。可是,同时在老生代,只能使用串行的标记清除方法。
老生代,必须作fullgc,必须从root开始全面标识收集。