- 浏览: 2469396 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (574)
- Book (62)
- Architecture (6)
- Java (39)
- Taobao (41)
- Distributed (4)
- Life (72)
- Database (7)
- Spring (16)
- Photography (15)
- Bicycle (41)
- Test (20)
- jBPM (8)
- Business (12)
- Movie (3)
- Ajax (15)
- Code (7)
- Eclipse (96)
- VIM (2)
- Music (6)
- Groovy (10)
- AutoHotKey (3)
- Dorado (10)
- Maven (7)
- Scrum (5)
- English (20)
- Financial (12)
- OSGi (3)
- Other (4)
- Tool (6)
- Browser (1)
- PPT (1)
- Project Management (4)
- Agile (6)
- Nosql (1)
- Search engine (6)
- Shell (2)
- Open Source (4)
- Storm (10)
- Guava (3)
- Baby (1)
- netty (1)
- Algorithm (1)
- Linux (1)
- Python (2)
最新评论
-
roy2011a:
https://github.com/ebottabi/sto ...
storm的序列化问题及与spring的结合方式 -
roy2011a:
能抗能打 写道哥们儿,你好!能共享下那个storm与sprin ...
storm的序列化问题及与spring的结合方式 -
Alick1:
兄弟,你之前是不是在深圳的正阳公司呆过啊?
storm的ack和fail -
liuleixwd:
先点个赞,写的非常好!有个问题请教下,如果我再bolt里不用e ...
storm的ack和fail -
yao-dd:
solr的facet查询
参考网址
http://pengjiaheng.spaces.live.com/blog/cns!2DAA368B386E6AEA!770.entry 这个讲的比较全面, 比较入门
http://blog.csdn.net/Peart_Boy/archive/2006/10/01/1313413.aspx 讲的基本概念不错, 虽然比较老(jdk1.3)
http://www.blogjava.net/yoda/archive/2008/04/14/192633.html 这个是jdk1.4的
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html 这个是最新的(jdk1.5), 可以与上面的中文的对照来看
http://blogs.sun.com/watt/resource/jvm-options-list.html 很全的参数说明(各个版本, 各个平台)
http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm jvm参数大全(jdk6 中文版)
http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx 这个对并行, 并发收集讲的比较好
http://www.iteye.com/topic/212967 比较有借鉴的调优实战
http://www.meichua.com/archives/tag/java-tool 常用jvm辅助工具
基本概念
stack and heap
stack, 又称线程栈, 一个线程独占, heap则会被多个线程共享, stack解决了线程如何执行, 如何处理数据, heap解决了数据如何存放, 存放在哪儿的问题. heap中存的是对象。stack中存的是基本数据类型和堆中对象的引用。Heap是 Java 程序的对象生活的地方,包含活的对象,死的对象以及剩余内存。
当对象不能被运行中的程序的指针所到达时,这些对象成为”垃圾“。
JVM 的堆大小决定了 VM 花费在收集垃圾上的时间和频度。
使用这个方法可以得到应用的空间使用量
heap结构
堆划分为两个区域:新生代和旧生代。新生代(Young)又分为:Eden 和两片生存空间(survivor spaces)。其中保证有一片空间在任何时间是空的,当垃圾收集发生时, Eden 中的活的对象复制到下一片生存空间,对象就在生存空间之间复制,直到到达最大门限值(老化),然后复制到旧生代。Eden 是新的对象分配的地方。
当-Xms参数的值比-Xmx小的时候, 会存在一个虚拟空间.
如果堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。
线程运行时需要分配内存, gc则负责回收内存, 为了解决二者的矛盾, 必须在gc的时候停止线程的运行来达到阻止分配内存的目的.
为了优化GC,最好让-Xmn值约等于-Xmx的1/3
Young代的默认值为4M,随堆内存增大,约为1/15, -XX:NewRatio= 参数可以设置Young与Old的大小比例,-server时默认为1:2,但实际上young启动时远低于这个比率?如果信不过JVM,也可以用-Xmn硬性规定其大小,有文档推荐设为Heap总大小的1/4。
Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
垃圾收集(GC)
垃圾收集可以接受的速度与应用有关,应该通过分析实际的垃圾收集的时间和频率来调整。
如果堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。
调整堆大小的的目的是最小化垃圾收集的时间,以在特定的时间内最大化处理客户的请求。
对象在年轻代生存的时间越长,需要的收集时间也越长,因此,收集变慢。
你的应用建立和释放对象的速度决定了垃圾收集的频度。因此,在编程时,应注意使用对象的缓冲,而不是新建立对象。
大多数对象在新生代就已经死去,因此你能有效的调整垃圾收集。如果你能安排大多数对象的生存期小于一个收集时间,那么,垃圾收集是十分高效的。
暂停时间的含义是应用因为垃圾收集而显示出来的短暂停顿。
吞吐量的含义是在一段比较长的时间内,没有用在垃圾收集的时间和总时间的百分比。
减少暂停时间的办法可以采用小的年轻代和增量收集,但是这以牺牲吞吐率为代价。
很大的新生代能提高吞吐率,但是会带来暂停时间的增加。
当某个代被充满的时候,就会发生垃圾收集,所以,吞吐量和可用内存的大小成反比,总内存大小是影响垃圾收集的最重要因素。
年轻代大点就不用频繁GC,而且增大GC的间隔后,可以让多点对象自己死掉而不用复制了。但Young增大时,GC造成的停顿时间会相应增加
并行(Parallel)与并发(Concurrent)仅一字之差,并行指多条垃圾收集线程并行,并发指用户线程与垃圾收集线程并发,程序在继续运行,而垃圾收集程序运行于另一个个CPU上。并行指多条垃圾收集线程并行,并发指用户线程与垃圾收集线程并发.
full gc对整个堆进行整理,包括Young、Tenured和Perm。
年轻代的复制收集,依然必须停止所有应用程序线程,原理如此,只能靠多CPU,多收集线程并发来提高收集速度
常用JVM参数说明
以 -X 开头的选项都为非标准选项(并不能在所有的 VM 上实现),在后续的版本中可能会不通知而变更。
由于 -XX 选项需要特别的系统权限,因此不建议随便使用。
-verbosegc
使用 -verbosegc 选项测量有多少时间和资源用于垃圾收集。
通过使用虚拟机选项-verbose:gc,能够将每次收集时的一些信息打印出来
上面的输出中,表明虚拟机进行了两次次要收集和一次主要收集。箭头两端的数字
325407K->83000K(第一行)
表示在进行垃圾收集之前和之后活动对象的总大小。在次要收集之后的数字(83000K)包含了那些并不是必要活动的对象,但是还不能被回收。因为这些对象可能本身是活动的,或者有来自旧生代的引用。括弧中的数字(776768K)(第一行)表示总共的可用空间的大小。这个大小不包括持久代在内,是堆的大小减去一个存活空间的大小。此次次要收集大约用了0.2300771 secs (第一行)
如果使用了-XX:+PrintGCDetail选项,就会将垃圾收集时的详细信息打印出来
[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]]
从上面的输出信息可以看出,次要收集释放了新生代大约98%的空间(DefNew: 64575K->959K(64576K))
用了大约46毫秒(0.0457646 secs)
整个堆空间的使用率下降到51%左右(196016K->133633K(261184K))
最后看到,相对于新生代的收集,在时间消耗上稍微多了一点点(0.0459067 secs)
-XX:+DisableExplicitGC 关闭程序中的System.gc()调用
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间。
输出形式:Application time: 0.5291524 seconds
-XX:+PrintGCApplicationStoppedTime打印垃圾回收期间程序暂停的时间。
输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析。
-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
输出形式:
-XX:+AggressiveHeap 特别说明下:(我感觉对于做java cache应用有帮助)
* 试图是使用大量的物理内存
* 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量)
* 至少需要256MB内存
* 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升)
-XX:+UseParNewGC 允许多线程收集新生代
-XX:+CMSParallelRemarkEnabled 降低标记停顿
-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 压缩内存, CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。
-XX:+UseCMSInitiatingOccupancyOnly 仅仅使用手动定义初始化定义开始CMS收集
-XX:CMSInitiatingOccupancyFraction=70 年老代上, 使用70%后开始CMS收集
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
-XX:+GCTimeRatio=19 垃圾回收时间(1)与非垃圾回收时间(19)的比值, 表示java可以用5%的时间来做垃圾回收,1/(1+19)=1 /20=5%, 默认情况为99,即1%的时间用于垃圾回收。
-XX:+CMSParallelRemarkEnabled 减少cms中第二次remark的时间
-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc, 减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。
GC信息的格式
<collector> GC为minor收集过程中使用的垃圾收集器起的内部名称.
<starting occupancy1> young generation 在进行垃圾收集前被对象使用的存储空间.
<ending occupancy1> young generation 在进行垃圾收集后被对象使用的存储空间
<pause time1> minor收集使应用暂停的时间长短(秒)
<starting occupancy3> 整个堆(Heap Size)在进行垃圾收集前被对象使用的存储空间
<ending occupancy3> 整个堆(Heap Size)在进行垃圾收集后被对象使用的存储空间
<pause time3> 整个垃圾收集使应用暂停的时间长短(秒),包括major收集使应用暂停的时间(如果发生了major收集).
收集器
-XX:+UseParallelGC。吞吐收集器(已默认无需配置的参数: -XX:+UseAdaptiveSizePolicy(动态调整新生代大小)). 并行收集使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,越能体现出并行收集器的优势。在新生代使用并行收集策略, 当你的应用运行在多个处理器的主机上时,考虑使用吞吐收集器。应用中有很多线程都在创建对象时, 需要增大新生代的大小。在只有1颗CPU的主机上,吞吐收集器的性能表现可能还不如默认收集器,因为一些并行执行(例如进行同步时的开销)带来了额外的开销;在2颗CPU的主机上,吞吐收集器和默认收集器性能相当;在多于2颗CPU的主机上,你会发现进行次要收集的暂停时间降低了。 年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,线程数默认为CPU个数,CPU很多时,可用–XX:ParallelGCThreads=减少线程数。增加收集线程, 会增加旧生代的内存碎片. 参数-XX:+UseAdaptiveSizePolicy(默认打开)。该特征对于收集时间、分配比例、收集之后堆的空闲空间等数据进行统计分析,然后以此为依据调整新生代和旧生代的大小以达到最佳效果。-XX:+AggressiveHeap选项会检测主机的资源(内存大小、处理器数量),然后调整相关的参数,使得长时间运行的、内存申请密集的任务能够以最佳状态运行。吞吐收集器(-XX:+UseParallelGC)、大小自适应(-XX:+UseAdaptiveSizePolicy)以及本选项(-XX:+AggressiveHeap)经常结合在一起使用。对年轻代的复制收集,依然必须停止所有应用程序线程,因此只能靠多CPU,多收集线程并发来提高收集速度
-XX:+UseConcMarkSweepGC。并发收集器(已默认无需配置的参数:-XX:+UseParNewGC(Parallel收集新生代) -XX:+CMSPermGenSweepingEnabled(CMS收集持久代) -XX:UseCMSCompactAtFullCollection(full gc时压缩年老代)). 在旧生代使用并发收集策略,大部分收集工作都是和应用并发进行的, 在进行收集的时候,应用的暂停时间很短(两次短暂停,其他时间应用程序与收集线程并发的清除)。如果设置一个合适的旧生代大小,能够达到非常良好的效果。并发收集器旨在降低旧生代上进行收集的暂停时间. 每当发生主要收集的时候,并发收集器在收集开始的时候和中期会短时间的暂停所有的应用线程,中期的暂停时间相对长一点,在这次暂停中,多个线程同时工作完成收集任务。剩余的收集工作将由一个收集线程完成,这次是和应用并发执行的。虽然降低了暂停时间,但是并发收集确实占用了一部分处理器资源,所以你可能感觉到应用会有所缓慢。N的值越大,在并发收集上所用的处理器资源就越少,并发收集器的优势就越明显。当采用-XX:+PrintGCDetails参数和-verbose:gc输出,我们可以看到并发收集的输出中穿插了很多次要收集,一个并发收集周期中,会有多次的次要收集。CMS-initial-mark表示并发收集周期的开始,CMS-concurrent-mark表示并发标识阶段的结束,CMS-concurrent-sweep表示并发清理阶段的结束。在多处理器平台上,可以使用参数-XX:+UseParNewGC来降低次要收集的暂停时间, 如果使用了UseParNewGC,那么同时使用-XX:+CMSParallelRemarkEnabled参数可以降低标识暂停. 并发收集一开始会很短暂的停止一次所有线程来开始初始标记根对象,然后标记线程与应用线程一起并发运行,最后又很短的暂停一次,多线程并行的重新标记之前可能因为并发而漏掉的对象,然后就开始与应用程序并发的清除过程。可见,最长的两个遍历过程都是与应用程序并发执行的,比以前的串行算法改进太多. 串行标记清除是等年老代满了再开始收集的,而并发收集因为要与应用程序一起运行,如果满了才收集,应用程序就无内存可用,所以系统默认68%满的时候就开始收集。内存已设得较大,吃内存又没有这么快的时候,可以用-XX:CMSInitiatingOccupancyFraction=恰当增大该比率。 使用CMS的前提条件是你有比较的长生命对象(比如有200M以上的OLD堆占用).
-Xincgc。增量收集器(jdk1.5已停止维护).
调优原则
两个重要的优化途径:总执行时间的最小化和由垃圾收集所引起的暂停时间的最小化。另一个选项是最小化花在执行垃圾收集操作上的总时间。
如果系统花费很多的时间收集垃圾,请减小堆大小。
一次完全的垃圾收集(full gc)应该不超过 3-5 秒。
一般说来,你应该使用物理内存的 80% 作为堆大小。
除非你遇到暂停的问题,否则,可以分配足够的内存给 JVM,缺省的 64MB 总是太小。
设置-Xms和-Xmx一样大,以避免虚拟机在收缩大小时的消耗。
NewSize 和 MaxNewSize 绑定新生代的长度的低端和高端,设置为一样大小时和 -Xms 和 -Xmx 一样解决新生代的预测时间。最好将新生代的大小设定为经过NewRatio参数计算出的大小的整倍数。
当增加了处理器之后,要相应的增加虚拟机内存大小,因为内存分配是可以并行进行的
对于需要很大堆内存的服务器应用来说,大于堆虚拟约定内存一半的Eden大小是没有任何意义的:只会发生主要收集。
如果有特殊需要,使用参数SurvivorRatio可以调整存活空间的大小,但是通常这个参数对性能的影响不那么重要。例如,-XX:SurvivorRatio=6就设定了每个存活空间和Eden的比率为1 :6,换句话说,就是每个存活空间占新生代大小的1/8(不是1/7,因为有两个存活空间)。
年轻代大小选择:
* 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
* 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
一般的Young Generation的大小是整个Heap size的1/4。Young generation的minor收集率应一般在70%以上。当然在实际的应用中需要根据具体情况进行调整。
调优技巧
除非你碰到过度的大收集或者暂停时间,否则分配足够的内存给新生代,缺省的 MaxNewSize (32MB) 往往太小。
先使用默认收集器,找到一个新生代和旧生代大小的合适的估算值,然后将旧生代的大小设置成和新生代一样大再去使用并发收集器。这只是一个非常粗略的近似值,至于实际上的最佳设置是由应用来决定的。
当旧生代在填满之前如果收集工作无法全部完成,那么就会暂停应用的线程来完成所有的收集工作。这就是我们所说的完全收集(full collections)。如果发现完全收集比较频繁,可能需要调整并发收集的相关参数。
在使用增量收集器前, 首先使用默认收集器找到一个合适的堆大小,如果此时主要收集的暂停时间还是无法满足应用需求,尝试调整各个代的大小,并且使用增量收集器,直到找到合适的堆设置。
使用CMS的好处是用尽量少的新生代、我的经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间。
新生代越大,次要回收发生的次数就越少。当然,对于一定大小的堆来说,新生代越大,就意味着旧生代越小,那么就会使得主要回收的次数增多。最佳选择应该参考应用创建的对象的存活周期来设定。
如果存活空间设置的太小,就会导致过于频繁的向旧生代复制对象;如果存活空间设置的太大,就会因为空闲而白白浪费。虚拟机的垃圾收集器都会为对象在复制到旧生代之前的反转复制次数选择一个阀值,通过设定这个阀值来保证存活空间一直处于半满状态。通过指定 -XX:+PrintTenuringDistribution参数可以观察到这个阀值,以及新生代中对象的"年龄".
对于Web服务器应用来说,吞吐量是要着重考虑的,而暂停时间可能由于网络的反应时间而不那么明显;而对于一个交互式图形界面的应用来说,即使是短暂的暂停都会带来非常不好的用户体验。
设置代的大小是在这些考虑因素之间作出的一个权衡。将新生代设置得很大会得到很好的吞吐性能,但是会增加暂停时间;反之,较小的新生代设置会减小暂停时间,但是降低了吞吐量。一个代的大小不应该影响在其他代上进行垃圾收集的频率和暂停时间。
采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿。
参见问题说明
1.常见的出现java.lang.StackOverflowError异常是无法返回的递归
2.promotion failed错误的原因是CMS来不及回收(CMS默认在年老代占到90%左右才会执行),年老代又没有足够的空间供GC把一些活的对象从年轻代移到年老代,所以执行Full GC. 一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置 CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不会出现promotion failed。在我的应用中Xmx是6000,Xmn是500,那么Xmx-Xmn是5500M,也就是年老代有5500 M,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还剩10%的空间是5500*10%=550M,所以即使Xmn(也就是年轻代共500M)里所有对象都搬到年老代里,550M的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的promotion failed
3.Concurrent mode failed的产生是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。
4.java.lang.OutOfMemoryError: PermGen space
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。
在VM args里面增加-XX:MaxPermSize=***m. 持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
java.lang.OutOfMemoryError: PermGen space => the permanent generation is full.
1. If an application loads a very large number of classes, then the size of the permanent generation might need to be increased using the -XX:MaxPermSize option.
2. Interned java.lang.String objects are also stored in the permanent generation.If an application interns a huge number of strings, the permanent generation might need to be increased from its default setting.
5.java.lang.OutOfMemoryError: Java heap space 在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息
应用举例
1.高并发, 多cpu, 大内存场景
-server
-Xmx3g
-Xms3g
-XX:MaxPermSize=128m
-XX:NewRatio=1 eden/old 的比例
-XX:SurvivorRatio=8 s/e的比例
-XX:+UseParallelGC
-XX:ParallelGCThreads=8
-XX:+UseParallelOldGC 这个是JAVA 6出现的参数选项
-XX:LargePageSizeInBytes=128m 内存页的大小, 不可设置过大, 会影响Perm的大小。
-XX:+UseFastAccessorMethods 原始类型的快速优化
-XX:+DisableExplicitGC 关闭System.gc()
2.针对低延迟的Java虚拟机调优选项
-Xmx512m
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseTLAB
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing
-XX:CMSIncrementalDutyCycleMin=0
-XX:CMSIncrementalDutyCycle=10
如果想最小化执行时间,通常最好是尽量减少垃圾收集次数,这可以通过设置一个更大的堆大小而做到。这将减少垃圾收集次数,但是会使垃圾收集时间变长,而且垃圾收集暂停时间会比使用低延迟选项时长。
http://pengjiaheng.spaces.live.com/blog/cns!2DAA368B386E6AEA!770.entry 这个讲的比较全面, 比较入门
http://blog.csdn.net/Peart_Boy/archive/2006/10/01/1313413.aspx 讲的基本概念不错, 虽然比较老(jdk1.3)
http://www.blogjava.net/yoda/archive/2008/04/14/192633.html 这个是jdk1.4的
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html 这个是最新的(jdk1.5), 可以与上面的中文的对照来看
http://blogs.sun.com/watt/resource/jvm-options-list.html 很全的参数说明(各个版本, 各个平台)
http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm jvm参数大全(jdk6 中文版)
http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx 这个对并行, 并发收集讲的比较好
http://www.iteye.com/topic/212967 比较有借鉴的调优实战
http://www.meichua.com/archives/tag/java-tool 常用jvm辅助工具
基本概念
stack and heap
stack, 又称线程栈, 一个线程独占, heap则会被多个线程共享, stack解决了线程如何执行, 如何处理数据, heap解决了数据如何存放, 存放在哪儿的问题. heap中存的是对象。stack中存的是基本数据类型和堆中对象的引用。Heap是 Java 程序的对象生活的地方,包含活的对象,死的对象以及剩余内存。
当对象不能被运行中的程序的指针所到达时,这些对象成为”垃圾“。
JVM 的堆大小决定了 VM 花费在收集垃圾上的时间和频度。
使用这个方法可以得到应用的空间使用量
System.out.println(Runtime.getRuntime().totalMemory());
heap结构
堆划分为两个区域:新生代和旧生代。新生代(Young)又分为:Eden 和两片生存空间(survivor spaces)。其中保证有一片空间在任何时间是空的,当垃圾收集发生时, Eden 中的活的对象复制到下一片生存空间,对象就在生存空间之间复制,直到到达最大门限值(老化),然后复制到旧生代。Eden 是新的对象分配的地方。
当-Xms参数的值比-Xmx小的时候, 会存在一个虚拟空间.
如果堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。
线程运行时需要分配内存, gc则负责回收内存, 为了解决二者的矛盾, 必须在gc的时候停止线程的运行来达到阻止分配内存的目的.
为了优化GC,最好让-Xmn值约等于-Xmx的1/3
Young代的默认值为4M,随堆内存增大,约为1/15, -XX:NewRatio= 参数可以设置Young与Old的大小比例,-server时默认为1:2,但实际上young启动时远低于这个比率?如果信不过JVM,也可以用-Xmn硬性规定其大小,有文档推荐设为Heap总大小的1/4。
Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
垃圾收集(GC)
垃圾收集可以接受的速度与应用有关,应该通过分析实际的垃圾收集的时间和频率来调整。
如果堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。
调整堆大小的的目的是最小化垃圾收集的时间,以在特定的时间内最大化处理客户的请求。
对象在年轻代生存的时间越长,需要的收集时间也越长,因此,收集变慢。
你的应用建立和释放对象的速度决定了垃圾收集的频度。因此,在编程时,应注意使用对象的缓冲,而不是新建立对象。
大多数对象在新生代就已经死去,因此你能有效的调整垃圾收集。如果你能安排大多数对象的生存期小于一个收集时间,那么,垃圾收集是十分高效的。
暂停时间的含义是应用因为垃圾收集而显示出来的短暂停顿。
吞吐量的含义是在一段比较长的时间内,没有用在垃圾收集的时间和总时间的百分比。
减少暂停时间的办法可以采用小的年轻代和增量收集,但是这以牺牲吞吐率为代价。
很大的新生代能提高吞吐率,但是会带来暂停时间的增加。
当某个代被充满的时候,就会发生垃圾收集,所以,吞吐量和可用内存的大小成反比,总内存大小是影响垃圾收集的最重要因素。
年轻代大点就不用频繁GC,而且增大GC的间隔后,可以让多点对象自己死掉而不用复制了。但Young增大时,GC造成的停顿时间会相应增加
并行(Parallel)与并发(Concurrent)仅一字之差,并行指多条垃圾收集线程并行,并发指用户线程与垃圾收集线程并发,程序在继续运行,而垃圾收集程序运行于另一个个CPU上。并行指多条垃圾收集线程并行,并发指用户线程与垃圾收集线程并发.
full gc对整个堆进行整理,包括Young、Tenured和Perm。
年轻代的复制收集,依然必须停止所有应用程序线程,原理如此,只能靠多CPU,多收集线程并发来提高收集速度
常用JVM参数说明
以 -X 开头的选项都为非标准选项(并不能在所有的 VM 上实现),在后续的版本中可能会不通知而变更。
由于 -XX 选项需要特别的系统权限,因此不建议随便使用。
-verbosegc
使用 -verbosegc 选项测量有多少时间和资源用于垃圾收集。
通过使用虚拟机选项-verbose:gc,能够将每次收集时的一些信息打印出来
引用
[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
上面的输出中,表明虚拟机进行了两次次要收集和一次主要收集。箭头两端的数字
325407K->83000K(第一行)
表示在进行垃圾收集之前和之后活动对象的总大小。在次要收集之后的数字(83000K)包含了那些并不是必要活动的对象,但是还不能被回收。因为这些对象可能本身是活动的,或者有来自旧生代的引用。括弧中的数字(776768K)(第一行)表示总共的可用空间的大小。这个大小不包括持久代在内,是堆的大小减去一个存活空间的大小。此次次要收集大约用了0.2300771 secs (第一行)
如果使用了-XX:+PrintGCDetail选项,就会将垃圾收集时的详细信息打印出来
[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]]
从上面的输出信息可以看出,次要收集释放了新生代大约98%的空间(DefNew: 64575K->959K(64576K))
用了大约46毫秒(0.0457646 secs)
整个堆空间的使用率下降到51%左右(196016K->133633K(261184K))
最后看到,相对于新生代的收集,在时间消耗上稍微多了一点点(0.0459067 secs)
-XX:+DisableExplicitGC 关闭程序中的System.gc()调用
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间。
输出形式:Application time: 0.5291524 seconds
-XX:+PrintGCApplicationStoppedTime打印垃圾回收期间程序暂停的时间。
输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析。
-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
输出形式:
引用
34.702: [GC {Heap before gc invocations=7:
def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)
to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000)
tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
}
, 0.0757599 secs]
def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)
to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000)
tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
}
, 0.0757599 secs]
-XX:+AggressiveHeap 特别说明下:(我感觉对于做java cache应用有帮助)
* 试图是使用大量的物理内存
* 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量)
* 至少需要256MB内存
* 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升)
-XX:+UseParNewGC 允许多线程收集新生代
-XX:+CMSParallelRemarkEnabled 降低标记停顿
-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 压缩内存, CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。
-XX:+UseCMSInitiatingOccupancyOnly 仅仅使用手动定义初始化定义开始CMS收集
-XX:CMSInitiatingOccupancyFraction=70 年老代上, 使用70%后开始CMS收集
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
-XX:+GCTimeRatio=19 垃圾回收时间(1)与非垃圾回收时间(19)的比值, 表示java可以用5%的时间来做垃圾回收,1/(1+19)=1 /20=5%, 默认情况为99,即1%的时间用于垃圾回收。
-XX:+CMSParallelRemarkEnabled 减少cms中第二次remark的时间
-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc, 减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。
GC信息的格式
引用
[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]
<collector> GC为minor收集过程中使用的垃圾收集器起的内部名称.
<starting occupancy1> young generation 在进行垃圾收集前被对象使用的存储空间.
<ending occupancy1> young generation 在进行垃圾收集后被对象使用的存储空间
<pause time1> minor收集使应用暂停的时间长短(秒)
<starting occupancy3> 整个堆(Heap Size)在进行垃圾收集前被对象使用的存储空间
<ending occupancy3> 整个堆(Heap Size)在进行垃圾收集后被对象使用的存储空间
<pause time3> 整个垃圾收集使应用暂停的时间长短(秒),包括major收集使应用暂停的时间(如果发生了major收集).
收集器
-XX:+UseParallelGC。吞吐收集器(已默认无需配置的参数: -XX:+UseAdaptiveSizePolicy(动态调整新生代大小)). 并行收集使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,越能体现出并行收集器的优势。在新生代使用并行收集策略, 当你的应用运行在多个处理器的主机上时,考虑使用吞吐收集器。应用中有很多线程都在创建对象时, 需要增大新生代的大小。在只有1颗CPU的主机上,吞吐收集器的性能表现可能还不如默认收集器,因为一些并行执行(例如进行同步时的开销)带来了额外的开销;在2颗CPU的主机上,吞吐收集器和默认收集器性能相当;在多于2颗CPU的主机上,你会发现进行次要收集的暂停时间降低了。 年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,线程数默认为CPU个数,CPU很多时,可用–XX:ParallelGCThreads=减少线程数。增加收集线程, 会增加旧生代的内存碎片. 参数-XX:+UseAdaptiveSizePolicy(默认打开)。该特征对于收集时间、分配比例、收集之后堆的空闲空间等数据进行统计分析,然后以此为依据调整新生代和旧生代的大小以达到最佳效果。-XX:+AggressiveHeap选项会检测主机的资源(内存大小、处理器数量),然后调整相关的参数,使得长时间运行的、内存申请密集的任务能够以最佳状态运行。吞吐收集器(-XX:+UseParallelGC)、大小自适应(-XX:+UseAdaptiveSizePolicy)以及本选项(-XX:+AggressiveHeap)经常结合在一起使用。对年轻代的复制收集,依然必须停止所有应用程序线程,因此只能靠多CPU,多收集线程并发来提高收集速度
-XX:+UseConcMarkSweepGC。并发收集器(已默认无需配置的参数:-XX:+UseParNewGC(Parallel收集新生代) -XX:+CMSPermGenSweepingEnabled(CMS收集持久代) -XX:UseCMSCompactAtFullCollection(full gc时压缩年老代)). 在旧生代使用并发收集策略,大部分收集工作都是和应用并发进行的, 在进行收集的时候,应用的暂停时间很短(两次短暂停,其他时间应用程序与收集线程并发的清除)。如果设置一个合适的旧生代大小,能够达到非常良好的效果。并发收集器旨在降低旧生代上进行收集的暂停时间. 每当发生主要收集的时候,并发收集器在收集开始的时候和中期会短时间的暂停所有的应用线程,中期的暂停时间相对长一点,在这次暂停中,多个线程同时工作完成收集任务。剩余的收集工作将由一个收集线程完成,这次是和应用并发执行的。虽然降低了暂停时间,但是并发收集确实占用了一部分处理器资源,所以你可能感觉到应用会有所缓慢。N的值越大,在并发收集上所用的处理器资源就越少,并发收集器的优势就越明显。当采用-XX:+PrintGCDetails参数和-verbose:gc输出,我们可以看到并发收集的输出中穿插了很多次要收集,一个并发收集周期中,会有多次的次要收集。CMS-initial-mark表示并发收集周期的开始,CMS-concurrent-mark表示并发标识阶段的结束,CMS-concurrent-sweep表示并发清理阶段的结束。在多处理器平台上,可以使用参数-XX:+UseParNewGC来降低次要收集的暂停时间, 如果使用了UseParNewGC,那么同时使用-XX:+CMSParallelRemarkEnabled参数可以降低标识暂停. 并发收集一开始会很短暂的停止一次所有线程来开始初始标记根对象,然后标记线程与应用线程一起并发运行,最后又很短的暂停一次,多线程并行的重新标记之前可能因为并发而漏掉的对象,然后就开始与应用程序并发的清除过程。可见,最长的两个遍历过程都是与应用程序并发执行的,比以前的串行算法改进太多. 串行标记清除是等年老代满了再开始收集的,而并发收集因为要与应用程序一起运行,如果满了才收集,应用程序就无内存可用,所以系统默认68%满的时候就开始收集。内存已设得较大,吃内存又没有这么快的时候,可以用-XX:CMSInitiatingOccupancyFraction=恰当增大该比率。 使用CMS的前提条件是你有比较的长生命对象(比如有200M以上的OLD堆占用).
-Xincgc。增量收集器(jdk1.5已停止维护).
调优原则
两个重要的优化途径:总执行时间的最小化和由垃圾收集所引起的暂停时间的最小化。另一个选项是最小化花在执行垃圾收集操作上的总时间。
如果系统花费很多的时间收集垃圾,请减小堆大小。
一次完全的垃圾收集(full gc)应该不超过 3-5 秒。
一般说来,你应该使用物理内存的 80% 作为堆大小。
除非你遇到暂停的问题,否则,可以分配足够的内存给 JVM,缺省的 64MB 总是太小。
设置-Xms和-Xmx一样大,以避免虚拟机在收缩大小时的消耗。
NewSize 和 MaxNewSize 绑定新生代的长度的低端和高端,设置为一样大小时和 -Xms 和 -Xmx 一样解决新生代的预测时间。最好将新生代的大小设定为经过NewRatio参数计算出的大小的整倍数。
当增加了处理器之后,要相应的增加虚拟机内存大小,因为内存分配是可以并行进行的
对于需要很大堆内存的服务器应用来说,大于堆虚拟约定内存一半的Eden大小是没有任何意义的:只会发生主要收集。
如果有特殊需要,使用参数SurvivorRatio可以调整存活空间的大小,但是通常这个参数对性能的影响不那么重要。例如,-XX:SurvivorRatio=6就设定了每个存活空间和Eden的比率为1 :6,换句话说,就是每个存活空间占新生代大小的1/8(不是1/7,因为有两个存活空间)。
年轻代大小选择:
* 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
* 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
一般的Young Generation的大小是整个Heap size的1/4。Young generation的minor收集率应一般在70%以上。当然在实际的应用中需要根据具体情况进行调整。
调优技巧
除非你碰到过度的大收集或者暂停时间,否则分配足够的内存给新生代,缺省的 MaxNewSize (32MB) 往往太小。
先使用默认收集器,找到一个新生代和旧生代大小的合适的估算值,然后将旧生代的大小设置成和新生代一样大再去使用并发收集器。这只是一个非常粗略的近似值,至于实际上的最佳设置是由应用来决定的。
当旧生代在填满之前如果收集工作无法全部完成,那么就会暂停应用的线程来完成所有的收集工作。这就是我们所说的完全收集(full collections)。如果发现完全收集比较频繁,可能需要调整并发收集的相关参数。
在使用增量收集器前, 首先使用默认收集器找到一个合适的堆大小,如果此时主要收集的暂停时间还是无法满足应用需求,尝试调整各个代的大小,并且使用增量收集器,直到找到合适的堆设置。
使用CMS的好处是用尽量少的新生代、我的经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间。
新生代越大,次要回收发生的次数就越少。当然,对于一定大小的堆来说,新生代越大,就意味着旧生代越小,那么就会使得主要回收的次数增多。最佳选择应该参考应用创建的对象的存活周期来设定。
如果存活空间设置的太小,就会导致过于频繁的向旧生代复制对象;如果存活空间设置的太大,就会因为空闲而白白浪费。虚拟机的垃圾收集器都会为对象在复制到旧生代之前的反转复制次数选择一个阀值,通过设定这个阀值来保证存活空间一直处于半满状态。通过指定 -XX:+PrintTenuringDistribution参数可以观察到这个阀值,以及新生代中对象的"年龄".
对于Web服务器应用来说,吞吐量是要着重考虑的,而暂停时间可能由于网络的反应时间而不那么明显;而对于一个交互式图形界面的应用来说,即使是短暂的暂停都会带来非常不好的用户体验。
设置代的大小是在这些考虑因素之间作出的一个权衡。将新生代设置得很大会得到很好的吞吐性能,但是会增加暂停时间;反之,较小的新生代设置会减小暂停时间,但是降低了吞吐量。一个代的大小不应该影响在其他代上进行垃圾收集的频率和暂停时间。
采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿。
参见问题说明
1.常见的出现java.lang.StackOverflowError异常是无法返回的递归
2.promotion failed错误的原因是CMS来不及回收(CMS默认在年老代占到90%左右才会执行),年老代又没有足够的空间供GC把一些活的对象从年轻代移到年老代,所以执行Full GC. 一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置 CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不会出现promotion failed。在我的应用中Xmx是6000,Xmn是500,那么Xmx-Xmn是5500M,也就是年老代有5500 M,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还剩10%的空间是5500*10%=550M,所以即使Xmn(也就是年轻代共500M)里所有对象都搬到年老代里,550M的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的promotion failed
3.Concurrent mode failed的产生是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。
4.java.lang.OutOfMemoryError: PermGen space
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。
在VM args里面增加-XX:MaxPermSize=***m. 持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
java.lang.OutOfMemoryError: PermGen space => the permanent generation is full.
1. If an application loads a very large number of classes, then the size of the permanent generation might need to be increased using the -XX:MaxPermSize option.
2. Interned java.lang.String objects are also stored in the permanent generation.If an application interns a huge number of strings, the permanent generation might need to be increased from its default setting.
5.java.lang.OutOfMemoryError: Java heap space 在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息
应用举例
1.高并发, 多cpu, 大内存场景
-server
-Xmx3g
-Xms3g
-XX:MaxPermSize=128m
-XX:NewRatio=1 eden/old 的比例
-XX:SurvivorRatio=8 s/e的比例
-XX:+UseParallelGC
-XX:ParallelGCThreads=8
-XX:+UseParallelOldGC 这个是JAVA 6出现的参数选项
-XX:LargePageSizeInBytes=128m 内存页的大小, 不可设置过大, 会影响Perm的大小。
-XX:+UseFastAccessorMethods 原始类型的快速优化
-XX:+DisableExplicitGC 关闭System.gc()
2.针对低延迟的Java虚拟机调优选项
-Xmx512m
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseTLAB
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing
-XX:CMSIncrementalDutyCycleMin=0
-XX:CMSIncrementalDutyCycle=10
如果想最小化执行时间,通常最好是尽量减少垃圾收集次数,这可以通过设置一个更大的堆大小而做到。这将减少垃圾收集次数,但是会使垃圾收集时间变长,而且垃圾收集暂停时间会比使用低延迟选项时长。
发表评论
-
使用Externalization更高效的实现java对象序列化
2012-04-04 22:38 3145Externalization没用过, 它通过牺牲默认序列化的 ... -
关于java的检查异常和非检查异常
2012-04-04 21:31 4967这里有一个关于java的检查异常和非检查异常的观点, 我比较赞 ... -
使用ThreadLocal保证DateFormat线程安全
2012-04-03 06:45 3602大家都知道DateFormat是线程非安全的, 一般在多线程环 ... -
使用枚举实现一个状态机
2012-04-02 23:14 3938非常巧妙的一个使用枚举的例子.原文见这里 interface ... -
一个同步队列例子
2012-04-02 21:35 1571这个用的也比较少, 做一个参考, 原文见这里 private ... -
一个读写锁的例子
2012-04-02 21:20 1531用的比较少, 做一个参考. 原文在这里 public clas ... -
如何计算一个合适的线程池大小参数
2012-04-02 20:57 9070原文在这里 下面是一个计算的框架代码: /** * A ... -
正确使用日志的10个技巧
2012-02-11 21:13 28852做一个苦逼的Java攻城师, 我们除了关心系统的架构这种hig ... -
Java编程最差实践
2012-02-04 17:54 26640原文地址:http://www.odi.ch/prog/des ... -
利用jOOR简化Java 反射使用
2012-01-15 20:39 5156原文:http://lukaseder.wordpress.c ... -
《Java Performance》书评
2012-01-15 18:32 2963原文: http://java.dzone.com/rev ... -
《细说Java》读书笔记
2011-10-05 15:01 1994国人写的, 感觉是一 ... -
《Java开发超级工具集》读书笔记
2011-09-28 08:59 2099"工欲善其事必先利其器", 在平时的开发 ... -
《effective java》 读书笔记
2011-07-02 14:52 7603读第一版已经是好几年前的事儿了, 现在想起来也没什么印象, ... -
用java实现"awk -d"功能(保留多行重复)
2010-06-07 21:48 3071一般用过linux脚本的都知道"awk -d&quo ... -
关于方法返回值的两种处理模式
2010-05-13 09:06 2029目前在处理返回值方面, ... -
log4j的输出转换模式
2009-12-12 10:02 1273转换模式(conversion pattern)为" ... -
java正则表达式用法举例
2009-12-08 11:27 4521java正则表达式真难用啊, 这里整理一个java正则表达式用 ... -
Ibatis TypeHandler使用总结
2009-11-25 19:33 16549ibatis中有一个TypeHandler(准确的说应该是Ty ... -
ibatis参数传递小技巧
2009-10-30 14:21 3922使用ibatis操作数据库的时候, 如果这个操作需要一些参数, ...
相关推荐
了解并熟练掌握这些GC算法和JVM调优技巧,对于解决性能问题、优化Java应用的运行效率至关重要,同时也是面试中经常被问到的话题。通过实践和理解,开发者可以更好地理解和控制JVM的行为,从而编写出更高效、更稳定的...
### JVM调优文档:垃圾收集(GC)与性能优化 #### 概述 Java虚拟机(JVM)作为运行Java程序的核心组件,其性能直接影响着应用程序的运行效率和稳定性。在JVM中,垃圾收集(GC)是自动管理内存的重要机制之一。本文...
(原创)JVM超详细知识点汇总,汇总了JVM内存模型,字节码,垃圾回收器,类加载器,JVM调优等众多非常详细的知识点。能够助你能深入完全的掌握JVM。
需要注意的是,进行JVM调优时,应该针对具体的应用场景和性能需求进行细致的分析和调整。参数的选择和配置应根据应用的特点和运行环境来进行。同时,JVM调优是一个持续的过程,需要不断地监控、测试和调整参数以获得...
3、 java高级:JVM调优 4、 Spring系列:spring 、SpringBoot 、SpringCloud系列等 IOC、AOP、事务问题 5、 消息中间件:MQ、Ribbt_MQ、Kafaka 6、 数据库系列:mysql redis 等 基础、进阶、sql优化等 7、 设计模式...
### Tomcat调优及相关汇总设置 #### 一、Tomcat防止恶意攻击 ##### 1. 管理平台安全设置 - **管理平台**: Tomcat自带的管理平台(manager)是一个web应用,可通过`localhost:8080/manager/html`进行访问。此平台...
《Tomcat调优及相关设置汇总》是一份详细探讨如何优化Apache Tomcat服务器性能的重要文档,由作者flowerd54编写。Tomcat作为广泛使用的开源Java Servlet容器,其性能调优对于提升Web应用的响应速度和处理能力至关...
《JVM调优总结.pdf》可能汇总了一些常见的调优经验和技巧。而《Java虚拟机基础.pdf》则是JVM的基础知识介绍,涵盖了其基本概念和运作方式。 理解并掌握这些知识,将有助于你编写出更高效、更稳定的Java应用程序,...
【JVM内存区域】 JVM(Java虚拟机)在运行时将内存划分为多个区域,以便高效管理和优化程序的执行。这些区域包括: ...通过深入学习JVM的内存管理机制,开发者可以更好地控制和调优Java应用程序。
5. **JVM调优**:包括JVM启动参数设置,如-Xms, -Xmx用于设置堆内存大小,-XX:NewRatio设置新生代与老年代的比例,-XX:SurvivorRatio设置Eden区与Survivor区的比例。此外,还有堆dump分析工具,如jmap和jhat。 6. *...
2. **JVM调优**: 如何通过JMX监控JVM,使用JVisualVM或JProfiler等工具进行性能分析,调整JVM参数以优化内存分配、垃圾回收效率和应用性能。 这些知识点不仅涵盖了Java语言的深度,还涉及了其在实际开发中的应用,...
GC日志通过-Xloggc和相关的选项可以记录,这对于分析和调优非常有用。-XX:CMSInitiatingOccupancyFraction参数用于设置CMS收集器在老年代占用多少比例时开始进行并发标记。当遇到OOM错误时,可以通过-XX:+...
最后,对于高级主题,如Spring框架、微服务、并发编程、JVM调优等,也是面试中可能会遇到的。Spring的核心概念如依赖注入(DI),AOP(面向切面编程),以及Spring Boot和Spring Cloud在微服务架构中的应用。对于...
Java虚拟机(JVM)是Java程序的核心组成部分,它负责执行字节码并管理内存...理解这些JVM概念对于开发和优化Java应用程序至关重要,特别是在处理内存管理和性能调优时。熟悉这些知识点将有助于应对JVM相关的面试挑战。
4. **JVM调优**:通过JMX、JConsole或VisualVM监控和调整JVM参数。 **MySQL** MySQL是一款常用的开源关系型数据库管理系统,面试中常涉及: 1. **SQL语法**:DML(增删改查)、DDL(定义表结构)、DCL(权限管理)...
在Java虚拟机(JVM)中,垃圾回收(Garbage Collection, GC)是自动管理内存的重要机制,它负责识别并释放不再使用的对象所占用的内存空间。...理解这些基础的垃圾回收算法有助于我们更好地调试和调优Java应用程序。
以下是一些关于JVM的常见面试题解析、指南和汇总。 ### 1. JVM内存模型 JVM内存主要分为以下几个区域: - **程序计数器**:记录当前线程正在执行的字节码指令地址。 - **虚拟机栈**:每个方法对应一个栈帧,存储...
在Java编程领域,面试中经常涉及的技术点涵盖了JVM内存模型、JVM调优、并发编程、框架应用等多个方面。以下是对这些知识点的详细解析: 1. **JVM内存模型**: - JVM运行时区域主要包括程序计数器、Java虚拟机栈、...
GC的性能优化是JVM调优的重要部分。"JVM 垃圾回收机制及性能调优案例"文档可能包含了如何调整JVM参数以改善系统性能的内容,比如设置新生代和老年代的大小、选择合适的GC策略、控制GC频率等。理解这些参数的意义和...